package com.leinao.project.service.impl;


import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.parser.Feature;
import com.github.pagehelper.PageHelper;
import com.google.common.collect.Lists;
import com.leinao.category.dao.CategoryMapper;
import com.leinao.category.dto.CategoryRelationDto;
import com.leinao.commons.Response;
import com.leinao.commons.ResponseMessage;
import com.leinao.config.EnvironmentConfig;
import com.leinao.constant.*;
import com.leinao.job.dao.PaiProjectJobMapper;
import com.leinao.job.dto.*;
import com.leinao.job.model.PaiProjectJob;
import com.leinao.login.dto.LoginResultDto;
import com.leinao.model.dao.ModelMapper;
import com.leinao.model.model.Model;
import com.leinao.project.dao.PaiDataSetMapper;
import com.leinao.project.dao.ProjectHistoryMapper;
import com.leinao.project.dao.ProjectMapper;
import com.leinao.project.dto.*;
import com.leinao.project.dto.bottomdata.Task1;
import com.leinao.project.dto.bottomdata.TaskRoles;
import com.leinao.project.dto.bottomdata.TaskStatus;
import com.leinao.project.model.*;
import com.leinao.project.service.ProjectService;
import com.leinao.util.BeanUtils;
import com.leinao.util.compare.ObjectCompare;
import com.leinao.util.page.PageInfo;
import com.leinao.util.random.RandomPrimaryCode;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.*;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;

import java.io.File;
import java.util.*;
import java.util.stream.Collectors;

/**
 *
 * @Description 项目服务
 * @author lizi
 * @date 2018/11/16 下午5:15
 * @Version 1.0
 */
@Service
public class ProjectServiceImpl implements ProjectService {
	
	private static Logger logger = LoggerFactory.getLogger(ProjectServiceImpl.class);

    @Autowired
    private ProjectMapper projectMapper;

    @Autowired
    private PaiDataSetMapper paiDataSetMapper;

    @Autowired
    private PaiProjectJobMapper paiProjectJobMapper;

    @Autowired
	private CategoryMapper categoryMapper;

	@Autowired
	private RestTemplate restTemplate;

	@Autowired
	private EnvironmentConfig env;

	@Autowired
	private ProjectHistoryMapper projectHistoryMapper;

    @Autowired
    private ModelMapper modelMapper;


	/**
     * 本地联调测试https API
     */
/*    static {
        HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {
            @Override
            public boolean verify(String hostname, SSLSession session) {
                return true;
            }
        });
    }*/

    /**
     * @Description 获取公开数据集的项目列表
     * @param datasetId : 数据集ID
     * @param pageNumber : 当前页
     * @param pageSize : 每页条数
     * @author lizi
     * @date 2018/11/16 下午5:31
     */
    @Override
    public Response<PageInfo> getProjectListByPublicDatasetId(Long datasetId, String userId, Integer pageNumber, Integer pageSize) {
        // 设置分页条件
        PageHelper.startPage(pageNumber, pageSize);

        List<PublicProjectListDto> publicProjectList = projectMapper.getPublicProjectListByPublicDatasetId(datasetId, userId);

		// 初始化公开项目分类信息
		initPublicProjectCategoryInfo(publicProjectList, 0L);

		// 初始化公开项目人员信息
		initPublicProjectUserInfo(publicProjectList);

        return Response.ok(new PageInfo<>(publicProjectList == null ? Collections.emptyList() : publicProjectList));
    }

    /**
     * @Description 获取我的数据集的项目列表
     * @param datasetId : 数据集ID
     * @param pageNumber : 当前页
     * @param pageSize : 每页条数
     * @author lizi
     * @date 2018/11/16 下午5:31
     */
    @Override
    public Response<PageInfo> getProjectListByPrivateDatasetId(Long datasetId, String userId, Integer pageNumber, Integer pageSize) {
        // 设置分页条件
        PageHelper.startPage(pageNumber, pageSize);

        // 数据集项目列表
        List<ProjectListDto> projectList = projectMapper.getProjectListByPrivateDatasetId(datasetId, userId);

        return Response.ok(new PageInfo<>(projectList == null ? Collections.emptyList() : projectList));

    }

    /**
     * @Description 获取公开项目列表
     * @param sortType : 排序方式，参见com.leinao.constant.PublicProjectSortTypeEnum
	 * @param categoryId : 分类ID
     * @param pageNumber : 当前页
     * @param pageSize : 每页条数
     * @author lizi
     * @date 2018/11/16 下午5:31
     */
    @Override
    public Response<PageInfo> getPublicProjectList(Integer sortType, Long categoryId, Integer pageNumber, Integer pageSize) {
        // 设置分页条件
        PageHelper.startPage(pageNumber, pageSize);

        // 数据集项目列表
        List<PublicProjectListDto> projectList = projectMapper.getPublicProjectList(sortType, categoryId);

        // 初始化公开项目人员信息
		initPublicProjectUserInfo(projectList);

		// 初始化公开项目分类信息
		initPublicProjectCategoryInfo(projectList, categoryId == null ? 0L : categoryId);

		return Response.ok(new PageInfo<>(projectList == null ? Collections.emptyList() : projectList));
    }

    /***
     * @Description 公开项目统计
     * @author lizi
     * @date 2018/11/29 下午7:19
     */
    @Override
    public Response<PublicProjectCollectDto> getPublicProjectCollectInfo() {
        PublicProjectCollectDto publicProjectCollectDto = projectMapper.getPublicProjectCollectInfo();
        return Response.ok(publicProjectCollectDto == null ? new PublicProjectCollectDto() : publicProjectCollectDto);
    }

	/***
	 * @Description 我的项目统计
	 * @author lizi
	 * @date 2018/11/29 下午7:19
	 */
	@Override
	public Response<ProjectCollectDto> getProjectCollectDto(String userId) {
		ProjectCollectDto projectCollectDto = projectMapper.getProjectCollectInfo(userId);
		return Response.ok(projectCollectDto == null ? new ProjectCollectDto() : projectCollectDto);
	}

	/***
     * @Description 获取数据集信息
     * @param datasetId : 数据集ID
     * @author lizi
     * @date 2018/11/27 下午8:40
     */
    @Override
    public PaiDataSet getDatasetByDatasetId(Long datasetId) {
        return paiDataSetMapper.getDatasetByDatasetId(datasetId);
    }

    /***
     * @Description 公开项目
     * @param publicProjectParamDto : 项目公开参数
     * @param userInfo : 用户信息
     * @author lizi
     * @date 2018/11/27 下午8:40
     */
    @Transactional(value ="transactionManager", propagation = Propagation.REQUIRED)
    @Override
    public Response<Project> openProject(PublicProjectParamDto publicProjectParamDto, LoginResultDto userInfo) {

        String token = userInfo.getToken();
		String userId = userInfo.getUserId();
		Long projectId = publicProjectParamDto.getProjectId();
		Long fileId = publicProjectParamDto.getFileId();
		List<Long> projectJobIdList = publicProjectParamDto.getProjectJobIdList() == null ? Collections.emptyList() : publicProjectParamDto.getProjectJobIdList();

		// 校验1.公开项目中的公开任务是否为空，如果未选择公开任务，返回提示
		if( null == projectJobIdList || projectJobIdList.size()<=0){
			return Response.error(Constant.RESPONSE_STATUS_SUCCESS, ProjectErrorEnum.OPEN_PROJECT_JOB_CAN_NOT_BE_NULL.getSeq(), ProjectErrorEnum.OPEN_PROJECT_JOB_CAN_NOT_BE_NULL.getDesc(),null);
		}

		// 获取该项目下的公开的任务列表信息
		List<PaiProjectJobDto> projectJobDtoList = paiProjectJobMapper.getProjectJobInfoListByJobIdList(projectId, projectJobIdList);
		projectJobDtoList = projectJobDtoList == null ? Collections.emptyList() : projectJobDtoList;

		// 校验2.任务ID是否都存在，比对数据库中查出来的List和前端传来projectJobIdList
		if(projectJobDtoList.size() != publicProjectParamDto.getProjectJobIdList().size()) {
			return Response.error(Constant.RESPONSE_STATUS_SUCCESS, ProjectErrorEnum.INVALID_PROJECT_JOB_ID.getSeq(), ProjectErrorEnum.INVALID_PROJECT_JOB_ID.getDesc(),null);
		}

		// 校验3.是否存在非普通任务，只有普通任务可以公开
		for(PaiProjectJobDto projectJobDto : projectJobDtoList) {
			if(!JobTypeEnum.COMMON.getType().equals(projectJobDto.getJobType())) {
				return Response.error(Constant.RESPONSE_STATUS_SUCCESS, ProjectErrorEnum.COMMON_JOB_CAN_PUBLIC.getSeq(), ProjectErrorEnum.COMMON_JOB_CAN_PUBLIC.getDesc(),null);
			}
		}

        // 获取项目信息
        Project project = projectMapper.getProject(projectId);
        if(null == project) {
            return Response.error(Constant.RESPONSE_STATUS_SUCCESS, ProjectErrorEnum.INVALID_PROJECT_ID.getSeq(), ProjectErrorEnum.INVALID_PROJECT_ID.getDesc(),null);
        }
        // 校验4.操作人是否项目拥有者，非项目拥有人，不可进行公开操作
        if(!userId.equals(project.getUserId())) {
            return Response.error(Constant.RESPONSE_STATUS_SUCCESS, ProjectErrorEnum.PROJECT_NO_AUTHORITY.getSeq(), ProjectErrorEnum.PROJECT_NO_AUTHORITY.getDesc(),null);
        }


        // a.任务状态验证
		// 请求任务信息地址拼接
		StringBuilder sb = new StringBuilder(env.getRestServerUrl() + Constant.REST_SERVER_BATCH_QUERY_JOB_API);
		for(PaiProjectJobDto ppj : projectJobDtoList) {
			logger.debug("jobName: {}", ppj.getJobName());
			sb.append(ppj.getJobName()).append(",");
		}
		String batchQueryJobInfoUrl = sb.toString();
		logger.debug("batchQueryJobInfoUrl: {}", batchQueryJobInfoUrl);
		// 公开任务中最新任务信息
		PaiProjectJobDto newestProjectJob = null;
		// 从底层查询出任务的信息
		List<JobInfoDto> jobInfoList = batchQueryJobInfo(batchQueryJobInfoUrl, userInfo.getToken());
		for(PaiProjectJobDto projectJob : projectJobDtoList) {
			//获取最新任务信息
			if(null == newestProjectJob){
				newestProjectJob = projectJob;
			}else if(newestProjectJob.getCodeNo()< projectJob.getCodeNo()){
				newestProjectJob = projectJob;
			}
			for(JobInfoDto jobInfo : jobInfoList) {
				String jobName = jobInfo.getJobName();
				if(projectJob.getJobName().equals(jobName)) {
				    //校验5.只有成功状态的任务才可以公开
				    if(!ProjectJobStateEnum.SUCCEEDED.getState().equals(jobInfo.getState())){
                        return Response.error(Constant.RESPONSE_STATUS_SUCCESS, ProjectErrorEnum.ONLY_SUCCESS_JOB_CAN_PUBLIC.getSeq(), ProjectErrorEnum.ONLY_SUCCESS_JOB_CAN_PUBLIC.getDesc(),null);
                    }
                    projectJob.setExecutionType(jobInfo.getExecutionType());
					projectJob.setRetries(jobInfo.getRetries());
				    projectJob.setCompletedTime(jobInfo.getCompletedTime());
				    projectJob.setStartedTime(jobInfo.getCreatedTime());
				    projectJob.setState(jobInfo.getState());
                    //b.获取任务日志
					JSONObject jsonObj = getJobDetail(jobName,token);
					TaskRoles taskRoles = JSON.parseObject(jsonObj.getString("taskRoles"), TaskRoles.class);
					Task1 task1 = taskRoles.getTask1();
					List<TaskStatus> taskStatuses = task1.getTaskStatuses();
					String containerLog = taskStatuses.get(0).getContainerLog();
					logger.info("loadJobDetail resp: {}", containerLog);
					projectJob.setJobLogUrl(containerLog);
				}
			}
		}

		// 公开项目任务代码快照
		//公开项目config为任务config，代码仓库为项目仓库，代码分支为任务的分支

		// 获取最新任务的配置信息
		String newestConfig = newestProjectJob.getConfig();

		// 公开项目参数信息和笔记
		long now = System.currentTimeMillis();

		// 获取该项目对应的公开项目Id
		Project publicProject = projectMapper.getPublicProjectByRelation(project.getId());

		if(publicProject == null) {
            publicProject = new Project();
			BeanUtils.copyProperties(project,publicProject);
			// 添加公开项目信息
			publicProject.setConfig(newestConfig);
			publicProject.setOrigin(ProjectOriginEnum.OPEN.getType());
			publicProject.setType(ProjectTypeEnum.PUBLIC.getType());
			publicProject.setGitTag(newestProjectJob.getGitTag());
			publicProject.setCreateTime(System.currentTimeMillis());
			publicProject.setUpdateTime(System.currentTimeMillis());
			projectMapper.createProject(publicProject);

			// 创建用户项目公开关系
			PaiUserProjectRelation userProjectRelation = new PaiUserProjectRelation();
			userProjectRelation.setProjectId(publicProject.getId());
			userProjectRelation.setSourceProjectId(project.getId());
			userProjectRelation.setType(UserProjectTypeEnum.OPEN.getType());
			userProjectRelation.setUserId(userId);
			userProjectRelation.setCreateTime(now);
			userProjectRelation.setUpdateTime(now);
			projectMapper.insertUserProjectRelation(userProjectRelation);
		} else {
		    //临时获取公开项目id
            Long publicId = publicProject.getId();
			// 逻辑 删除原先公开的任务信息
			paiProjectJobMapper.deleteProjectJobs(publicId);
			//拷贝项目中最新属性到公开项目中
            BeanUtils.copyProperties(project,publicProject);
			// 编辑项目信息
            publicProject.setId(publicId);
			publicProject.setConfig(newestConfig);
            publicProject.setGitTag(newestProjectJob.getGitTag());
			publicProject.setUpdateTime(System.currentTimeMillis());
			projectMapper.editProject(publicProject);
			// 删除公开项目封面关系, 最后会重新插入封面
			projectMapper.deletePublicProjectCover(publicProject.getId());
		}
		// 公开项目id
		Long publicId = publicProject.getId();

		//记录所有公开项目历史信息
		ProjectHistory projectHistory = new ProjectHistory();
		projectHistory.initProjectHistory(publicProject);
		projectHistoryMapper.createProject(projectHistory);
		// 插入公开任务信息并且记录历史公开记录
		for(PaiProjectJobDto projectJob : projectJobDtoList) {
			ProjectPublicJob publicJob = new ProjectPublicJob();
			// 任务信息拷贝到公开任务信息中
			BeanUtils.copyProperties(projectJob,publicJob);
			publicJob.setProjectJobId(projectJob.getId());
            publicJob.setProjectId(publicId);
            publicJob.setJobCreateTime(projectJob.getCreateTime());
            publicJob.setCreateTime(now);
			// 将公开任务信息插入数据库
			paiProjectJobMapper.insertPublicJob(publicJob);
			projectJob.setProjectPublicJobId(publicJob.getId());
			paiProjectJobMapper.updateProjectJobInfo(projectJob);

			//公开历史任务信息
			ProjectPublicJobHistory projectPublicJobHistory = new ProjectPublicJobHistory();
			BeanUtils.copyProperties(publicJob,projectPublicJobHistory);
			projectPublicJobHistory.setProjectHistoryId(projectHistory.getId());
			projectPublicJobHistory.setProjectPublicJobId(publicJob.getId());
			projectPublicJobHistory.setProjectJobId(projectJob.getId());
			paiProjectJobMapper.insertPublicJobHistory(projectPublicJobHistory);

		}

		// 复制项目和数据集关系
		copyProjectDataSetRelation(project.getId(), publicId);
		// 复制项目和模型关系
		copyProjectModelRelation(project.getId(), publicId);

		// 保存公开项目封面图片
		PaiObjectFileRelation pofr = new PaiObjectFileRelation();
		pofr.setFileId(fileId);
		pofr.setType(ObjectFileTypeEnum.FILE_TYPE_OPENPROJECT.getSeq());
		pofr.setObjId(publicId);
		pofr.setCreateTime(System.currentTimeMillis());
		pofr.setUpdateTime(System.currentTimeMillis());
		//插入公开项目封面图片
        projectMapper.insertObjFileRelation(pofr);

        //插入 pai_project_dataset_relation_history、pai_object_file_relation_history、pai_object_category_relation_history
		insertProjectRelationHistory(publicId,projectHistory.getId());

        return Response.ok( publicProject);
    }

	/**
	 * @description 查询任务底层信息，获取任务的容器信息和任务状态。
	 * @param jobName 任务名
	 * @param token 用户token
	 * @return JSONObject 返回底层数据
	 * @author  guoliangbo
	 * @date 2019.5.9 11:40:00
	 */
	private JSONObject getJobDetail(String jobName, String token) {
		HttpHeaders headers = new HttpHeaders();
		MediaType type = MediaType.parseMediaType("application/json; charset=UTF-8");
		headers.setContentType(type);
		headers.add("Accept", MediaType.APPLICATION_JSON.toString());
		headers.add("Authorization", "Bearer " + token);
		HttpEntity<String> formEntity = new HttpEntity<String>(null, headers);
		String body = "";
		try {
			ResponseEntity<String> responseEntity = restTemplate.exchange(env.getRestServerUrl() + Constant.REST_SERVER_LOAD_JOB_API + jobName,
					HttpMethod.GET, formEntity, String.class);
			logger.debug(String.format("request getJobDetail return: {}", JSON.toJSON(responseEntity)));
			if (responseEntity.getStatusCodeValue() == Constant.RESPONSE_STATUS_SUCCESS) {
				logger.debug("loadJobDetail success");
				body = responseEntity.getBody();
				JSONObject jsonObj = JSON.parseObject(body);
				logger.info(String.format("loadJobDetail resp: {}", jsonObj));
				return jsonObj;
			}
		} catch (Exception e) {
			logger.error("loadJobDetail error");
			logger.error(e.getMessage(), e);
			return null;
		}
		return null;
	}

	/**
	  * 功能描述：插入 项目历史记录
	 * 	 *  pai_project_dataset_relation_history
	 * 	 *  pai_object_file_relation_history
	 * 	 *  pai_object_category_relation_history
	  * @param projectId 项目id
	  * @param publicHistoryId 公开项目历史表id
	  * @return void
	  * @Author: guoliangbo
	  * @Date: 2019/5/27 17:41
	  */
	private void insertProjectRelationHistory(Long projectId,Long publicHistoryId) {
		//插入项目和文件关系记录
		projectMapper.insertProjectFileRelationHistory(projectId,publicHistoryId);
		//插入数据集和项目关系记录
		projectMapper.insertProjectDatasetRelationHistory(projectId,publicHistoryId);
		//插入项目和类别关系记录
		projectMapper.insertProjectCategoryRelationHistory(projectId,publicHistoryId);
	}

	/***
	 * @Description 复制项目
	 * @param projectId : 项目ID
	 * @param userInfo : 用户信息
	 * @author lizi
	 * @date 2018/11/29 下午8:40
	 */
	@Override
	public Response<CopyProjectResult> copyProject(Long projectId, String jobIds, LoginResultDto userInfo) {

		// 获取项目信息
		Project project = projectMapper.getProject(projectId);
		if(project == null) {
			return Response.error(Constant.RESPONSE_STATUS_SUCCESS,
					ProjectErrorEnum.INVALID_PROJECT_ID.getSeq(), ProjectErrorEnum.INVALID_PROJECT_ID.getDesc(), null);
		}

		// 项目是否公开
		if(!ProjectTypeEnum.PUBLIC.getType().equals(project.getType())) {
			return Response.error(Constant.RESPONSE_STATUS_SUCCESS,
					ProjectErrorEnum.PROJECT_NOT_PUBLIC.getSeq(), ProjectErrorEnum.PROJECT_NOT_PUBLIC.getDesc(), null);
		}

		//判断任务是否公开
		String[] jobIdsArr = jobIds.split(",");
		List<String> list = Lists.newArrayList();
		for (String jobId : jobIdsArr) {
			list.add(jobId);
		}

		List<ProjectPublicJobDto> publicJobs = projectMapper.getPublicJobs(list);
		if(list.size() != publicJobs.size()){
			return Response.error(Constant.RESPONSE_STATUS_SUCCESS,
					ProjectErrorEnum.PROJECT_IS_NOT_PUBLIC.getSeq(), ProjectErrorEnum.PROJECT_IS_NOT_PUBLIC.getDesc(), null);
		}

		// 获取用户下非公开的项目名称列表
		String userId = userInfo.getUserId();
		List<String> projectNameList = projectMapper.getProjectNameListByUserIdAndProjectType(userId, ProjectTypeEnum.PERSON.getType());
		String copyProjectName = generateProjectName(project.getProjectName(), projectNameList);

        // 需要克隆的任务信息初始化
		List<String> tagList = new ArrayList<>();
		Integer maxTag = 0;
		List<PaiProjectJob> projectJobs = Lists.newArrayList();
		for (int i = 0; i < publicJobs.size(); i++) {
			PaiProjectJob paiProjectJob = new PaiProjectJob();
			paiProjectJob.setCodeNo(publicJobs.get(i).getCodeNo());
			paiProjectJob.setJobName(publicJobs.get(i).getJobName());
			paiProjectJob.setConfig(publicJobs.get(i).getConfig());
			paiProjectJob.setProjectName(publicJobs.get(i).getProjectName());
			paiProjectJob.setRemark(publicJobs.get(i).getRemark());
			paiProjectJob.setDelFlag(publicJobs.get(i).getDelFlag());
			paiProjectJob.setCreateTime(publicJobs.get(i).getCreateTime());
			paiProjectJob.setUpdateTime(publicJobs.get(i).getUpdateTime());
			paiProjectJob.setJobType(publicJobs.get(i).getJobType());
			paiProjectJob.setGitTag(publicJobs.get(i).getGitTag());
			paiProjectJob.setProjectPublicJobId(publicJobs.get(i).getId());
			paiProjectJob.setQuoteOutputPath(publicJobs.get(i).getQuoteOutputPath());
			paiProjectJob.setHyperParameter(publicJobs.get(i).getHyperParameter());
			paiProjectJob.setState(publicJobs.get(i).getState());
			paiProjectJob.setExecutionType(publicJobs.get(i).getExecutionType());
			paiProjectJob.setRetries(publicJobs.get(i).getRetries());
			paiProjectJob.setStartedTime(publicJobs.get(i).getStartedTime());
			paiProjectJob.setCompletedTime(publicJobs.get(i).getCompletedTime());
			paiProjectJob.setJobLogUrl(publicJobs.get(i).getJobLogUrl());
			projectJobs.add(paiProjectJob);

			// 任务标签记录
			tagList.add(paiProjectJob.getCodeNo().toString());
			maxTag = maxTag > paiProjectJob.getCodeNo() ? maxTag : paiProjectJob.getCodeNo();
		}


		// 此处的实现通过git clone代码，然后删除原始仓库地址，再次初始化仓库
		MultiValueMap<String, String> paramMap = new LinkedMultiValueMap<>();
		paramMap.add("projectId", projectId.toString());
		paramMap.add("projectName", copyProjectName);
		String timestamp = String.valueOf(System.currentTimeMillis());
		paramMap.add("timestamp", timestamp);
		// 实际的任务分支标签
		paramMap.add("maxTag", maxTag.toString());
		paramMap.add("tags", String.join(",", tagList.toArray(new String[]{})));
		Response<String> response = requestFileCenter(paramMap, userInfo, Constant.FILE_CENTER_PROJECT_CLONE_REPOSITORY_API);
		String gitRepository;
		if(response.getMessage().getCode() == ResponseMessage.SUCCESS_CODE) {
			gitRepository = response.getData();
		} else {
            return Response.ok(Constant.RESPONSE_STATUS_SUCCESS, ProjectErrorEnum.REPOSITORY_INIT_FAILURE.getSeq(),
                                                        ProjectErrorEnum.REPOSITORY_INIT_FAILURE.getDesc(), null);
		}

		// 项目代码目录： /projects/_dc0eca94ae81410299dd5f67fb1538a6/config-test/code
		String projectPath = env.getProjectPath() + userId + File.separator + copyProjectName + Constant.PROJECT_CODE_STRUCTURE;

		// 修改项目配置中的jobName参数
		String config = modifyProjectConfig(project.getConfig());
		// 复制项目参数信息和笔记
		long now = System.currentTimeMillis();
		Project copyProject = new Project();
		copyProject.setProjectName(copyProjectName);
		copyProject.setType(ProjectTypeEnum.PERSON.getType());
		copyProject.setProfile(project.getProfile());
		copyProject.setConfig(config);
		copyProject.setNotes(project.getNotes());
		copyProject.setCreateTime(now);
		copyProject.setUpdateTime(now);

		copyProject.setUserId(userId);
		copyProject.setFilePath(projectPath);
		copyProject.setAlgorithm(project.getAlgorithm());
		copyProject.setLanguage(project.getLanguage());
		copyProject.setOrigin(ProjectOriginEnum.COPY.getType());
		// 克隆项目代码仓库 地址
		copyProject.setGitRepository(gitRepository);
		copyProject.setGitTimestamp(timestamp);


		// 创建用户项目复制关系
		PaiUserProjectRelation userProjectRelation = new PaiUserProjectRelation();
		userProjectRelation.setCreateTime(now);
		userProjectRelation.setUpdateTime(now);
		userProjectRelation.setSourceProjectId(projectId);
		userProjectRelation.setType(UserProjectTypeEnum.COPY.getType());
		userProjectRelation.setUserId(userId);

		CopyProjectResult copyProjectResult = new CopyProjectResult();
		copyProjectResult.setCopyProject(copyProject);
		copyProjectResult.setProjectId(projectId);
		copyProjectResult.setUserProjectRelation(userProjectRelation);
		copyProjectResult.setProjectJobs(projectJobs);

		logger.info("copyProject param  copyProjectResult: {}", copyProjectResult);
		return Response.ok(copyProjectResult);
	}

	/**
	  * @Description   克隆项目入库
	  * @param copyProjectResult	克隆项目信息
	  * @param userInfo 用户信息
	  * @return
	  * @author:    weiwei
	  * @Date:  2019/6/10 19:05
	  */
	@Transactional(value ="transactionManager", propagation = Propagation.REQUIRED)
	@Override
	public Response<Long> copyProjectInsert(CopyProjectResult copyProjectResult, LoginResultDto userInfo) {

		logger.info("copyProjectInsert param  copyProjectResult: {}", copyProjectResult);
		Project copyProject = copyProjectResult.getCopyProject();
		projectMapper.createProject(copyProjectResult.getCopyProject());

		List<PaiProjectJob> projectJobs = copyProjectResult.getProjectJobs();
		for (int i = 0; i < projectJobs.size(); i++) {
			projectJobs.get(i).setProjectId(copyProject.getId());
		}

		PaiUserProjectRelation userProjectRelation = copyProjectResult.getUserProjectRelation();
		userProjectRelation.setProjectId(copyProject.getId());
		projectMapper.insertUserProjectRelation(userProjectRelation);

		// 复制项目和数据集关系
		copyProjectDataSetRelation(copyProjectResult.getProjectId(), copyProject.getId());

		//复制项目和模型的关系
		copyProjectModelRelations(copyProjectResult.getProjectId(), copyProject.getId());

		//克隆任务
		paiProjectJobMapper.copyJobs(projectJobs);

		return Response.ok(copyProject.getId());
	}


	/**
	  * @Description 	复制项目和模型的关系
	  * @param srcProjectId		克隆项目Id
	  * @param targetProjectId		复制项Id
	  * @return
	  * @author:    weiwei
	  * @Date:  2019/6/14 20:00
	  */
	private void copyProjectModelRelations(Long srcProjectId, Long targetProjectId) {
		//查询项目模型关系列表
		List<Long> modelIdList = modelMapper.selectModelIdListByProjectId(srcProjectId);

		// 所有需要添加的项目数据集关系列表
		Set<Long> modelIdSet = new LinkedHashSet<>();
		if(!CollectionUtils.isEmpty(modelIdList)) {
			modelIdSet.addAll(modelIdList);
		}

		// 需要新增的项目数据集关系列表
		List<Long> insertModelIdList = new ArrayList<>(modelIdSet);
		if(!CollectionUtils.isEmpty(insertModelIdList)) {
			long now = System.currentTimeMillis();
			List<ProjectModelDto> projectModelRelationList = new ArrayList<>();
			insertModelIdList.forEach(modelId -> {
				ProjectModelDto projectModelRelation = new ProjectModelDto();
				projectModelRelation.setModelId(modelId);
				projectModelRelation.setProjectId(targetProjectId);
				projectModelRelation.setUpdateTime(now);
				projectModelRelation.setCreateTime(now);
				projectModelRelationList.add(projectModelRelation);
			});
			modelMapper.batchInsertProjectModelRelation(projectModelRelationList);
		}
	}


	/***
	 * @Description 编辑项目
	 * @param project : 项目
	 * @param userId : 用户ID
	 * @author lizi
	 * @date 2018/11/29 下午8:40
	 */
	@Transactional(value ="transactionManager", propagation = Propagation.REQUIRED)
	@Override
	public Response<Void> editProject(Project project, String userId) {
		// 获取项目信息
		Long projectId = project.getId();
		if(projectId == null || projectId == 0) {
			return Response.error(Constant.RESPONSE_STATUS_SUCCESS, ProjectErrorEnum.INVALID_PROJECT_ID.getSeq(), ProjectErrorEnum.INVALID_PROJECT_ID.getDesc(), null);
		}
		Project dbProject = projectMapper.getProject(projectId);
		if(dbProject == null) {
			return Response.error(Constant.RESPONSE_STATUS_SUCCESS, ProjectErrorEnum.INVALID_PROJECT_ID.getSeq(), ProjectErrorEnum.INVALID_PROJECT_ID.getDesc(), null);
		}
		if(!dbProject.getUserId().equals(userId)) {
			return Response.error(Constant.RESPONSE_STATUS_SUCCESS, ProjectErrorEnum.PROJECT_NO_AUTHORITY.getSeq(), ProjectErrorEnum.PROJECT_NO_AUTHORITY.getDesc());
		}

		// 复制项目参数信息和笔记
		long now = System.currentTimeMillis();
		project.setUpdateTime(now);
		projectMapper.editProjectTemplate(project);

		// 项目数据集关系列表
		List<Long> dbDatasetIdList = paiDataSetMapper.selectDataSetIdListByProjectId(projectId);
		dbDatasetIdList = dbDatasetIdList == null ? Collections.emptyList() : dbDatasetIdList;
		
		// 所有需要添加的项目数据集关系列表
		Set<Long> datasetIdSet = new LinkedHashSet<>();
		if(!CollectionUtils.isEmpty(project.getDataSetIdList())) {
			datasetIdSet.addAll(project.getDataSetIdList());
		}

		// 需要删除的项目数据集关系列表
		List<Long> deleteDatasetIdList = new ArrayList<>(dbDatasetIdList);
		deleteDatasetIdList.removeAll(datasetIdSet);
		if(!CollectionUtils.isEmpty(deleteDatasetIdList)) {
			paiDataSetMapper.deleteProjectDatasetRelation(projectId, deleteDatasetIdList);
		}

		// 需要新增的项目数据集关系列表
		List<Long> insertDatasetIdList = new ArrayList<>(datasetIdSet);
		insertDatasetIdList.removeAll(dbDatasetIdList);
		if(!CollectionUtils.isEmpty(insertDatasetIdList)) {
			insertProjectDataSetRelation(projectId, insertDatasetIdList);
		}

		return Response.ok();
	}

	/***
	 * @Description 查询项目笔记
	 * @param projectId : 项目ID
	 * @param userId : 用户ID
	 * @author lizi
	 * @date 2018/11/29 下午8:40
	 */
	@Override
	public Response<ProjectNotes> getProjectNotes(Long projectId, String userId) {
		// 获取项目信息
		Project project = projectMapper.getProject(projectId);
		if(project == null) {
			return Response.error(Constant.RESPONSE_STATUS_SUCCESS, ProjectErrorEnum.INVALID_PROJECT_ID.getSeq(), ProjectErrorEnum.INVALID_PROJECT_ID.getDesc(), null);
		}

		// 是否有权限查看项目笔记
		if(!ProjectTypeEnum.PUBLIC.getType().equals(project.getType()) && !project.getUserId().equals(userId)) {
			return Response.error(Constant.RESPONSE_STATUS_SUCCESS, ProjectErrorEnum.PROJECT_NO_AUTHORITY.getSeq(), ProjectErrorEnum.PROJECT_NO_AUTHORITY.getDesc(), null);
		}

		ProjectNotes projectNotes = new ProjectNotes();
		projectNotes.setId(projectId);
		projectNotes.setNotes(project.getNotes());
		return Response.ok(projectNotes);
	}

	/***
	 * @Description 编辑项目笔记
	 * @param projectNotes : 项目笔记信息
	 * @param userId : 用户ID
	 * @author lizi
	 * @date 2018/11/29 下午8:40
	 */
	@Transactional(value ="transactionManager", propagation = Propagation.REQUIRED)
	@Override
	public Response<Void> editProjectNotes(ProjectNotes projectNotes, String userId) {
		// 获取项目信息
		Long projectId = projectNotes.getId();
		if(projectId == null || projectId == 0) {
			return Response.error(Constant.RESPONSE_STATUS_SUCCESS, ProjectErrorEnum.INVALID_PROJECT_ID.getSeq(), ProjectErrorEnum.INVALID_PROJECT_ID.getDesc(), null);
		}
		Project project = projectMapper.getProject(projectId);
		if(project == null) {
			return Response.error(Constant.RESPONSE_STATUS_SUCCESS, ProjectErrorEnum.INVALID_PROJECT_ID.getSeq(), ProjectErrorEnum.INVALID_PROJECT_ID.getDesc(), null);
		}

		// 是否有权限编辑项目笔记
		if(!project.getUserId().equals(userId)) {
			return Response.error(Constant.RESPONSE_STATUS_SUCCESS, ProjectErrorEnum.PROJECT_NO_AUTHORITY.getSeq(), ProjectErrorEnum.PROJECT_NO_AUTHORITY.getDesc(), null);
		}

		// 保存项目笔记
		projectNotes.setUpdateTime(System.currentTimeMillis());
		projectMapper.editProjectNotes(projectNotes);

		return Response.ok();
	}

	/***
	 * @Description 获取公开项目明细
	 * @param projectId : 项目ID
	 * @author lizi
	 * @date 2018/11/29 下午4:21
	 */
	@Override
	public Response<Project> getPublicProjectDetail(Long projectId) {
		// 获取项目信息
		Project project = projectMapper.getProject(projectId);
		if(project == null) {
			return Response.error(Constant.RESPONSE_STATUS_SUCCESS, ProjectErrorEnum.INVALID_PROJECT_ID.getSeq(), ProjectErrorEnum.INVALID_PROJECT_ID.getDesc(), null);
		}

		// 项目是否公开
		if(!ProjectTypeEnum.PUBLIC.getType().equals(project.getType())) {
			return Response.error(Constant.RESPONSE_STATUS_SUCCESS, ProjectErrorEnum.PROJECT_NOT_PUBLIC.getSeq(), ProjectErrorEnum.PROJECT_NOT_PUBLIC.getDesc(), null);
		}

		return Response.ok(project);
	}

	/**
	 * 功能描述：项目创建
	 * @param project 项目信息
	 * @param dataSetIds 数据集ids
	 * @param userInfo 用户信息
	 * @return com.leinao.commons.Response<java.lang.Object>
	 * @Author: guoliangbo
	 * @Date: 2019/5/7 13:41
	 */
	@Transactional(rollbackFor=RuntimeException.class)
	@Override
	public Response<Project> createProject(Project project, String dataSetIds, String modelIds, LoginResultDto userInfo) {
		try {
			// 检查项目名是否存在
			boolean existProjectName = projectMapper.existProjectName(project.getProjectName(), userInfo.getUserId());
			if(existProjectName) {
				return Response.ok(Constant.RESPONSE_STATUS_SUCCESS, ProjectErrorEnum.PROJECT_NAME_FAILED.getSeq(), ProjectErrorEnum.PROJECT_NAME_FAILED.getDesc(), null);
			}

			// 代码仓库初始化
			MultiValueMap<String, String> paramMap = new LinkedMultiValueMap<>();
			String timestamp = String.valueOf(System.currentTimeMillis());
			paramMap.add("projectName", project.getProjectName());
			paramMap.add("timestamp", timestamp);
			Response<String> response = requestFileCenter(paramMap, userInfo, Constant.FILE_CENTER_PROJECT_INIT_REPOSITORY_API);
			if(response.getMessage().getCode() == ResponseMessage.SUCCESS_CODE) {
				project.setGitRepository(response.getData());
				project.setGitTimestamp(timestamp);
			} else {
				return Response.ok(Constant.RESPONSE_STATUS_SUCCESS, response.getMessage().getCode(), response.getMessage().getMessage(), null);
			}

			project.setUserId(userInfo.getUserId());
			project.setType(ProjectEnum.PROJECT_TYPE_OPEN_NO.getSeq());
			String filePath =  project.getFilePath();
			if (StringUtils.isNotBlank(filePath)) {
				if(!filePath.startsWith(Constant.FILE_PATH_SEPARATOR)) {
					filePath = Constant.FILE_PATH_SEPARATOR + filePath;
				}
				String codePath = env.getProjectPath() + userInfo.getUserId() + filePath;
				project.setFilePath(codePath);
			}
			long currentTimeMillis = System.currentTimeMillis();
			project.setCreateTime(currentTimeMillis);
			project.setUpdateTime(currentTimeMillis);
			project.setOrigin(ProjectOriginEnum.CREATE.getType());
			// TODO: 项目config属性中的路径都要前端进行修改
			Long num = projectMapper.createProject(project);
			logger.info("createProject return primary key: {}, num: {}", project.getId(), num);
			// insert pai_project_dataset_relation
			if (StringUtils.isNotBlank(dataSetIds)) {
				String[] dataIds = dataSetIds.split(",");
				List<ProjectDataSetDto> list = Lists.newArrayList();
				for (String dataSetId : dataIds) {
					ProjectDataSetDto pd = new ProjectDataSetDto();
					pd.setProjectId(project.getId());
					pd.setDataSetId(Long.parseLong(dataSetId));
					pd.setCreateTime(currentTimeMillis);
					pd.setUpdateTime(currentTimeMillis);
					list.add(pd);
				}
				projectMapper.batchInsertProjectDataSetRel(list);
			}

			//insert pai_project_model_relation
			if (StringUtils.isNotBlank(modelIds)) {
				String[] modelIdArr = modelIds.split(",");
				List<ProjectModelDto> list = Lists.newArrayList();
				for (String modelId : modelIdArr) {
					ProjectModelDto pm = new ProjectModelDto();
					pm.setProjectId(project.getId());
					pm.setModelId(Long.parseLong(modelId));
					pm.setCreateTime(currentTimeMillis);
					pm.setUpdateTime(currentTimeMillis);
					list.add(pm);
				}
				projectMapper.batchInsertProjectModelRel(list);
			}

			return Response.ok(Constant.RESPONSE_STATUS_SUCCESS, ProjectErrorEnum.PROJECT_SUCCESS.getSeq(),
					ProjectErrorEnum.PROJECT_SUCCESS.getDesc(), project);
		} catch (Exception e) {
			logger.error("createProject error by userId: {}", project.getUserId());
			logger.error(e.getMessage(), e);
			TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
			if(e.toString().contains("MySQLIntegrityConstraintViolationException")) {
				return Response.ok(Constant.RESPONSE_STATUS_SUCCESS, ProjectErrorEnum.PROJECT_NAME_FAILED.getSeq(), ProjectErrorEnum.PROJECT_NAME_FAILED.getDesc(), null);
			}
			return Response.ok(Constant.RESPONSE_STATUS_SUCCESS, ProjectErrorEnum.CREATE_PROJECT_FAILED.getSeq(),
					ProjectErrorEnum.CREATE_PROJECT_FAILED.getDesc(), null);
		}
	}
	
	/**
	 * 
	 * 更新项目配置
	 * 新建时仅保存、编辑项目调用该接口
	 * 
	 * @param project 项目信息
	 * @param dataSetIds 数据集字符串
	 * @param userInfo 用户信息
	 * @return
	 * @author wangshoufa 
	 * @date 2019年3月12日
	 *
	 */
	@Transactional(rollbackFor=RuntimeException.class)
	@Override
	public Response<Project> operateProject(Project project, String dataSetIds, String modelIds,  LoginResultDto userInfo) {
		try {
			if(StringUtils.isNotBlank(project.getConfig())) {
				String config = project.getConfig();
				if(config.contains("\"minSucceededTaskCount\":\"\"")) {
					config.replace("\"minSucceededTaskCount\":\"\"", "\"minSucceededTaskCount\":null");
				}
				if(config.contains("\"minFailedTaskCount\":\"\"")) {
					config.replace("\"minFailedTaskCount\":\"\"", "\"minFailedTaskCount\":null");
				}
				project.setConfig(config);
			}

			// 文件路径处理
			String filePath =  project.getFilePath();
			if (StringUtils.isNotBlank(filePath)) {
				if(!filePath.startsWith(Constant.FILE_PATH_SEPARATOR)) {
					filePath = Constant.FILE_PATH_SEPARATOR + filePath;
				}
				String codePath = env.getProjectPath() + userInfo.getUserId() + filePath;
				project.setFilePath(codePath);
			}

			long currentTimeMillis = System.currentTimeMillis();
			project.setUpdateTime(currentTimeMillis);
			// TODO: 项目config属性中的路径都要前端进行修改
			int num = projectMapper.editProject(project);
			logger.info("operateProject return primary key: {}, num: {}", project.getId(), num);

			//update pai_project_dataset_relation
			projectMapper.deleteProjectDataSetRelByProjectId(project.getId());
			if(StringUtils.isNotBlank(dataSetIds)) {
				//解除老关系
				//新增新关系
				String[] dataIds = dataSetIds.split(",");
				List<ProjectDataSetDto> list = Lists.newArrayList();
				for(String dataSetId : dataIds) {
					ProjectDataSetDto pd = new ProjectDataSetDto();
					pd.setProjectId(project.getId());
					pd.setDataSetId(Long.parseLong(dataSetId));
					pd.setCreateTime(currentTimeMillis);
					pd.setUpdateTime(currentTimeMillis);
					list.add(pd);
				}
				projectMapper.batchInsertProjectDataSetRel(list);
			}


			projectMapper.deleteProjectModelRelByProjectId(project.getId());
			if(StringUtils.isNotBlank(modelIds)) {
				//解除老关系
				//新增新关系
				String[] modelIdArr = modelIds.split(",");
				List<ProjectModelDto> list = Lists.newArrayList();
				for(String modelId : modelIdArr) {
					ProjectModelDto pm = new ProjectModelDto();
					pm.setModelId(Long.parseLong(modelId));
					pm.setProjectId(project.getId());
					pm.setUpdateTime(currentTimeMillis);
					pm.setCreateTime(currentTimeMillis);
					list.add(pm);
				}
				projectMapper.batchInsertProjectModelRel(list);
			}

			return Response.ok(Constant.RESPONSE_STATUS_SUCCESS, ProjectErrorEnum.OPERATE_PROJECT_SUCCESS.getSeq(), ProjectErrorEnum.OPERATE_PROJECT_SUCCESS.getDesc(), project);
		}
		catch (Exception e) {
			logger.error("operateProject error by userId: {}, projectName: {}", project.getUserId(), project.getProjectName());
			logger.error(e.getMessage(), e);
			TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
			return Response.ok(Constant.RESPONSE_STATUS_SUCCESS, ProjectErrorEnum.OPERATE_PROJECT_FAILED.getSeq(), ProjectErrorEnum.OPERATE_PROJECT_FAILED.getDesc(), null);
		}
	}

	/**
	  * @Description 仅保存任务
	  * @param project
	  * @param userInfo
	  * @return
	  * @author:    weiwei
	  * @Date:  2019/6/14 20:49
	  */
	@Transactional(rollbackFor=RuntimeException.class)
	@Override
	public Response<Project> saveJob(Project project, LoginResultDto userInfo) {
		try {
			if(StringUtils.isNotBlank(project.getConfig())) {
				String config = project.getConfig();
				if(config.contains("\"minSucceededTaskCount\":\"\"")) {
					config.replace("\"minSucceededTaskCount\":\"\"", "\"minSucceededTaskCount\":null");
				}
				if(config.contains("\"minFailedTaskCount\":\"\"")) {
					config.replace("\"minFailedTaskCount\":\"\"", "\"minFailedTaskCount\":null");
				}
				project.setConfig(config);
			}

			// 文件路径处理
			String filePath =  project.getFilePath();
			if (StringUtils.isNotBlank(filePath)) {
				if(!filePath.startsWith(Constant.FILE_PATH_SEPARATOR)) {
					filePath = Constant.FILE_PATH_SEPARATOR + filePath;
				}
				String codePath = env.getProjectPath() + userInfo.getUserId() + filePath;
				project.setFilePath(codePath);
			}

			long currentTimeMillis = System.currentTimeMillis();
			project.setUpdateTime(currentTimeMillis);
			// TODO: 项目config属性中的路径都要前端进行修改
			int num = projectMapper.editProject(project);
			logger.info("operateProject return primary key: {}, num: {}", project.getId(), num);

			return Response.ok(Constant.RESPONSE_STATUS_SUCCESS, ProjectErrorEnum.OPERATE_PROJECT_SUCCESS.getSeq(), ProjectErrorEnum.OPERATE_PROJECT_SUCCESS.getDesc(), project);
		}
		catch (Exception e) {
			logger.error("operateProject error by userId: {}, projectName: {}", project.getUserId(), project.getProjectName());
			logger.error(e.getMessage(), e);
			TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
			return Response.ok(Constant.RESPONSE_STATUS_SUCCESS, ProjectErrorEnum.OPERATE_PROJECT_FAILED.getSeq(), ProjectErrorEnum.OPERATE_PROJECT_FAILED.getDesc(), null);
		}
	}


    /**
     * 
     * 获取我的项目列表
     * @param userId 用户id
	 * @param origin : 项目创建来源：null-所有，0-自己创建，1-复制
     * @param cp 当前页数
     * @param ps 每页条数
     * @return
     * @author wangshoufa 
     * @date 2018年11月28日
     *
     */
	@Override
	public Response<PageInfo> getProjectList(String userId, Integer origin, Integer cp, Integer ps) {
		PageInfo pageInfo=null;
		PageHelper.startPage(cp, ps);
		List<ProjectListDto> list = Lists.newArrayList();
		try {
			list = projectMapper.queryProjectList(userId, origin);
			pageInfo = new PageInfo(list);
			return Response.ok(pageInfo);
		} catch (Exception e) {
			logger.error(e.getMessage(), e);
			return Response.error(Constant.RESPONSE_STATUS_SUCCESS, ProjectEnum.GET_PROJECT_ERROR.getSeq(),ProjectEnum.GET_PROJECT_ERROR.getDesc(),null);
		}
	}

	/**
	 * 获取项目的明细、任务展示列表
	 * @param projectId 项目id
	 * @param cp 任务的分页
	 * @param ps 每页条数
	 * @return
	 * @author wangshoufa 
	 * @date 2018年11月28日
	 *
	 */
	@Override
	public Response<PageInfo> getProjectJobInfo(Long projectId,String jobTag,String taskStatus, String token, Integer cp, Integer ps) {
		try {
			// 定义返回值
			PageInfo<JobInfoDto> page = new PageInfo<>();

			List<PaiProjectJobDto> list = projectMapper.getProjectJobInfo(projectId, jobTag);
			if(CollectionUtils.isNotEmpty(list)) {
				StringBuilder sb = new StringBuilder(env.getRestServerUrl() + Constant.REST_SERVER_BATCH_QUERY_JOB_API);
				for(PaiProjectJobDto ppj : list) {
					logger.debug("jobName: {}", ppj.getJobName());
					sb.append(ppj.getJobName()).append(",");
				}
				String batchQueryJobInfoUrl = sb.toString();
				logger.debug("batchQueryJobInfoUrl: {}", batchQueryJobInfoUrl);
				List<JobInfoDto> jobInfoList = batchQueryJobInfo(batchQueryJobInfoUrl, token);
				for(PaiProjectJobDto projectJob : list) {
					for(JobInfoDto jobInfo : jobInfoList) {
						if(projectJob.getJobName().equals(jobInfo.getJobName())) {
                            jobInfo.setCodeNo(projectJob.getCodeNo());
                            jobInfo.setJobType(projectJob.getJobType());
                            jobInfo.setId(projectJob.getId());
							jobInfo.setTensorboardUrl(projectJob.getTensorboardUrl());
                            jobInfo.setJobTag(projectJob.getJobTag());
                            jobInfo.setRemark(projectJob.getRemark());
                        }
					}
				}

				// 任务状态筛选
                if(StringUtils.isNotEmpty(taskStatus)){
                    jobInfoList.removeIf(projectJobView -> {
                        ProjectJobStateEnum jobStateParamEnum = ProjectJobStateEnum.enumOf(taskStatus);
                        ProjectJobStateEnum jobStateResultEnum = ProjectJobStateEnum.enumOf(projectJobView.getState());
                        // 状态为STOPPED和STOPPING合并为STOPPED分类
                        if(ProjectJobStateEnum.STOPPED == jobStateParamEnum && ProjectJobStateEnum.STOPPING == jobStateResultEnum) {
                            return false;
                        }
                        return !taskStatus.equalsIgnoreCase(projectJobView.getState());
                    });
                }

                // 任务排序
                Collections.sort(jobInfoList, new ObjectCompare<>(JobInfoDto.class.getDeclaredField("codeNo"), ObjectCompare.DIRECT_DESC, ObjectCompare.SORT_TYPE_COMPARABLE_VALUE));

				// 获取当前页数据
				List<JobInfoDto> currentJobInfoDtoList = new ArrayList<>();
				int currIndex = (cp > 1 ? (cp -1) * ps : 0);
				for (int i = 0; i < ps && i < jobInfoList.size() - currIndex; i++) {
					JobInfoDto jobInfoDto = jobInfoList.get(currIndex + i);
					currentJobInfoDtoList.add(jobInfoDto);
				}

				page.setList(currentJobInfoDtoList);
				page.setCurrentPage(cp);
				page.setPageSize(ps);
				page.setTotal(jobInfoList.size());
			}
			return Response.ok(page);
		} catch (Exception e) {
			logger.error(e.getMessage(), e);
			return Response.error(Constant.RESPONSE_STATUS_SUCCESS, ProjectEnum.GET_PROJECT_DETAIL_ERROR.getSeq(),ProjectEnum.GET_PROJECT_DETAIL_ERROR.getDesc(),null);
		}
	}

	/**
	 * @description 批量查询任务信息
	 * @param batchQueryJobInfoUrl 多个任务信息地址
	 * @param token rest-server认证token信息
	 * @author wangshoufa
	 * @date 2018年11月28日
	 */
	private List<JobInfoDto> batchQueryJobInfo(String batchQueryJobInfoUrl, String token){
		logger.info("batchQueryJobInfoUrl: {}", batchQueryJobInfoUrl);
		List<JobInfoDto> list = Lists.newArrayList();
		HttpHeaders headers = new HttpHeaders();
		MediaType type = MediaType.parseMediaType("application/json; charset=UTF-8");
		headers.setContentType(type);
		headers.add("Accept", MediaType.APPLICATION_JSON.toString());
		headers.add("Authorization", "Bearer " + token);
		HttpEntity<String> formEntity = new HttpEntity<String>(null, headers);
		String body = "";
		try {
			ResponseEntity<String> responseEntity = restTemplate.exchange(batchQueryJobInfoUrl,
					HttpMethod.GET, formEntity, String.class);
			logger.info("request batchQueryJobInfo return: {}", JSON.toJSON(responseEntity));
			if (responseEntity.getStatusCodeValue() == 200) {
				logger.info("batchQueryJobInfo success");
				body = responseEntity.getBody();
				JSONArray parseArray = JSON.parseArray(body);
				logger.info("batchQueryJobInfo resp: {}", parseArray);
				for(int i = 0; i < parseArray.size(); i++) {
					JobInfoDto jobInfo = getJobInfoByJsonObject(parseArray.getJSONObject(i));
					list.add(jobInfo);
				}

				return list;
			}
			return list;
		} catch (Exception e) {
			logger.error("batchQueryJobInfo error");
			logger.error(e.getMessage(), e);
			return list;
		}
	}

	/**
	 * json任务信息转换
	 *
	 * @param jsonObject 任务json信息
	 * @author wangshoufa
	 * @date 2019年06月06日
	 */
	private JobInfoDto getJobInfoByJsonObject(JSONObject jsonObject) {
		JobInfoDto jobInfo = new JobInfoDto();
		String jobName = jsonObject.getString("name");
		String userId = jsonObject.getString("userId");
		String state = jsonObject.getString("state");
		String executionType = jsonObject.getString("executionType");
		Integer retries = jsonObject.getInteger("retries");
		//获取任务中容器最早的启动时间，且设置为任务创建时间
		JSONObject taskRoleDetailInfo = jsonObject.getJSONObject("taskRoleDetailInfo");
		Long createdTime=0L;
		Long completedTime=0L;
		//用时
		Long timeConsuming=0L;
		if(taskRoleDetailInfo != null && !taskRoleDetailInfo.isEmpty()){
			Set<String> keys = taskRoleDetailInfo.keySet();
			List<Long> containerLaunchedTimestampList=new ArrayList<Long>();
			List<Long> containerCompletedTimestampList=new ArrayList<Long>();
			Iterator iterator = keys.iterator();
			while(iterator.hasNext()){
				String key = (String) iterator.next();
				Object taskRole =taskRoleDetailInfo.get(key);
				Object taskStatuses = JSON.parseObject(taskRole.toString()).get("taskStatuses");
				JSONArray taskStatusArray = JSON.parseObject(taskStatuses.toString()).getJSONArray("taskStatusArray");

				for (int j = 0; j < taskStatusArray.size(); j++) {
					JSONObject obj = (JSONObject) taskStatusArray.get(j);
					Long containerLaunchedTimestamp = obj.getLong("containerLaunchedTimestamp");
					Long containerCompletedTimestamp = obj.getLong("containerCompletedTimestamp");
					if(containerLaunchedTimestamp==null){
						containerLaunchedTimestamp=0L;
					}
					if(containerCompletedTimestamp==null){
						containerCompletedTimestamp=0L;
					}
					containerLaunchedTimestampList.add(containerLaunchedTimestamp);
					containerCompletedTimestampList.add(containerCompletedTimestamp);
				}
			}

			if(containerLaunchedTimestampList.size()>0){
				createdTime=Collections.min(containerLaunchedTimestampList);
			}
			if(containerCompletedTimestampList.size()>0){
				completedTime=Collections.max(containerCompletedTimestampList);
			}
		}
		if(Constant.JOB_STATUS_NOT_FOUND.equals(state)){
			createdTime=0L;
			completedTime=0L;
			timeConsuming=0L;
		}
		if(Constant.JOB_STATUS_WAITING.equals(state)){
			createdTime=0L;
			completedTime=0L;
			timeConsuming=0L;
		}
		if(Constant.JOB_STATUS_RUNNING.equals(state)){
		    if(createdTime>0){
                timeConsuming=(long)Math.ceil(Math.max(0,(System.currentTimeMillis()-createdTime))/1000);
            }else{
                state = Constant.JOB_STATUS_WAITING;
                createdTime=0L;
                completedTime=0L;
                timeConsuming=0L;
            }
		}
		if(Constant.JOB_STATUS_SUCCEEDED.equals(state)){
			timeConsuming=(long)Math.ceil(Math.max(0,(completedTime-createdTime))/1000);
		}
		if(Constant.JOB_STATUS_FAILED.equals(state)&&createdTime>0&&completedTime>0){
			timeConsuming=(long)Math.ceil(Math.max(0,(completedTime-createdTime))/1000);
		}
		if(Constant.JOB_STATUS_STOPPED.equals(state)&&createdTime>0&&completedTime>0){
			timeConsuming=(long)Math.ceil(Math.max(0,(completedTime-createdTime))/1000);
		}
		jobInfo.setTimeConsuming(timeConsuming);
		jobInfo.setJobName(jobName);
		jobInfo.setUserId(userId);
		jobInfo.setState(state);
		jobInfo.setExecutionType(executionType);
		jobInfo.setRetries(retries);
		jobInfo.setCompletedTime(completedTime);
		jobInfo.setCreatedTime(createdTime);
		return jobInfo;
	}

	/**
	 * @description 计算retry times
	 * @param jobInfo
	 * @param frameworkRetryPolicyState
	 * @author wangshoufa
	 * @date 2018年11月28日
	 */
	private void addRetries(JobInfoDto jobInfo, Object frameworkRetryPolicyState) {
		Integer retries = 0;
		JSONObject obj = JSON.parseObject(frameworkRetryPolicyState.toString());
		Integer retriedCount = obj.getInteger("retriedCount");
		Integer succeededRetriedCount = obj.getInteger("succeededRetriedCount");
		Integer transientNormalRetriedCount = obj.getInteger("transientNormalRetriedCount");
		Integer transientConflictRetriedCount = obj.getInteger("transientConflictRetriedCount");
		Integer nonTransientRetriedCount = obj.getInteger("nonTransientRetriedCount");
		Integer unKnownRetriedCount = obj.getInteger("unKnownRetriedCount");
		retries = retriedCount + succeededRetriedCount + transientNormalRetriedCount + transientConflictRetriedCount
				+ nonTransientRetriedCount + unKnownRetriedCount;
		jobInfo.setRetries(retries);
	}

    /**
     * @description 变更任务的状态
     * @param jobInfo
     * @param frameworkState
     * @param applicationExitCode
     */
	private void convertJobState(JobInfoDto jobInfo, String frameworkState, String applicationExitCode) {
		String state = "";
		switch (frameworkState) {
		case "FRAMEWORK_WAITING":
		case "APPLICATION_CREATED":
		case "APPLICATION_LAUNCHED":
		case "APPLICATION_WAITING":
			state = "WAITING";
            break;
		case "APPLICATION_RUNNING":
		case "APPLICATION_RETRIEVING_DIAGNOSTICS":
		case "APPLICATION_COMPLETED":
            state = "RUNNING";
            break;
		case "FRAMEWORK_COMPLETED":
            if (StringUtils.isNotBlank(applicationExitCode) && applicationExitCode.compareTo("0") == 0) {
                state = "SUCCEEDED";
            } else if (StringUtils.isNotBlank(applicationExitCode) && applicationExitCode.compareTo("214") == 0) {
                state = "STOPPED";
            } else {
                state = "FAILED";
            }
            break;
        default:
            state = "UNKNOWN";
		}
		jobInfo.setState(state);
	}

	/**
	 * @Description 获取任务视图列表
	 * @param taskStatus : 根据任务状态过滤数据（null或空字符串: 所有数据，WAITING: 正在等待的任务，RUNNING: 正在运行的任务，STOPPED: 暂定的任务，SUCCEEDED: 已结束的任务）
	 * @param pageNumber : 当前页
	 * @param pageSize : 每页条数
	 * @param userInfo : 用户信息
	 * @author lizi
	 * @date 2018/11/29 下午5:31
	 */
	@Override
	public Response<PageInfo> getTaskViewList(String taskStatus,String jobTag, Integer pageNumber, Integer pageSize, LoginResultDto userInfo) {
		// 定义返回值
		PageInfo<ProjectJobViewDto> page = new PageInfo<>();

		// 数据集项目任务列表
		List<ProjectJobViewDto> projectJobViewList = getProjectJobListForTag(userInfo,jobTag);

		// 根据任务状态过滤数据
		if(StringUtils.isNotEmpty(taskStatus) && CollectionUtils.isNotEmpty(projectJobViewList)) {
			projectJobViewList.removeIf(projectJobView -> {
				ProjectJobStateEnum jobStateParamEnum = ProjectJobStateEnum.enumOf(taskStatus);
				ProjectJobStateEnum jobStateResultEnum = ProjectJobStateEnum.enumOf(projectJobView.getState());
				// 状态为STOPPED和STOPPING合并为STOPPED分类
				if(ProjectJobStateEnum.STOPPED == jobStateParamEnum && ProjectJobStateEnum.STOPPING == jobStateResultEnum) {
					return false;
				}
				return !taskStatus.equalsIgnoreCase(projectJobView.getState());
			});
		}

		// 获取当前页数据
		List<ProjectJobViewDto> currentProjectJobViewDtoList = new ArrayList<>();
		if(CollectionUtils.isNotEmpty(projectJobViewList)) {
			int currIndex = (pageNumber > 1 ? (pageNumber -1) * pageSize : 0);
			for (int i = 0; i < pageSize && i < projectJobViewList.size() - currIndex; i++) {
				ProjectJobViewDto projectJobViewDto = projectJobViewList.get(currIndex + i);
				currentProjectJobViewDtoList.add(projectJobViewDto);
			}
		}
		page.setList(currentProjectJobViewDtoList);
		page.setCurrentPage(pageNumber);
		page.setPageSize(pageSize);
		page.setTotal(projectJobViewList == null ? 0 : projectJobViewList.size());

		return Response.ok(page);
	}

	/**
	 * @Description 项目数据集关系复制
	 * @param srcProjectId :
	 * @param targetProjectId :
	 * @author lizi
	 * @date 2018/12/4 下午4:18
	 */
	private void copyProjectDataSetRelation(Long srcProjectId, Long targetProjectId) {
		//  被公开项目数据集关系列表
		List<Long> datasetIdList = paiDataSetMapper.selectDataSetIdListByProjectId(srcProjectId);

		// 公开后的项目和数据集关系列表
		List<Long> dbDatasetIdList = paiDataSetMapper.selectDataSetIdListByProjectId(targetProjectId);

		// 所有需要添加的项目数据集关系列表
		Set<Long> datasetIdSet = new LinkedHashSet<>();
		if(!CollectionUtils.isEmpty(datasetIdList)) {
			datasetIdSet.addAll(datasetIdList);
		}

		// 需要删除的项目数据集关系列表
		List<Long> deleteDatasetIdList = new ArrayList<>(dbDatasetIdList);
		deleteDatasetIdList.removeAll(datasetIdSet);
		if(!CollectionUtils.isEmpty(deleteDatasetIdList)) {
			paiDataSetMapper.deleteProjectDatasetRelation(targetProjectId, deleteDatasetIdList);
		}

		// 需要新增的项目数据集关系列表
		List<Long> insertDatasetIdList = new ArrayList<>(datasetIdSet);
		insertDatasetIdList.removeAll(dbDatasetIdList);
		if(!CollectionUtils.isEmpty(insertDatasetIdList)) {
			insertProjectDataSetRelation(targetProjectId, insertDatasetIdList);
		}
	}

    /**
     * @Description 项目模型关系复制
     * @param srcProjectId : 待公开项目id
     * @param targetProjectId : 公开项目id
     * @author guoliangbo
     * @date 2019/06/14 下午6:43
     */
    private void copyProjectModelRelation(Long srcProjectId, Long targetProjectId) {
        //  被公开项目 模型关系列表
        List<Long> modelIdList = modelMapper.selectModelIdListByProjectId(srcProjectId);

        // 公开后的项目和数据集关系列表
        List<Long> dbModelIdList = modelMapper.selectModelIdListByProjectId(targetProjectId);

        // 所有需要添加的项目数据集关系列表
        Set<Long> modelIdSet = new LinkedHashSet<>();
        if(!CollectionUtils.isEmpty(modelIdList)) {
            modelIdSet.addAll(modelIdList);
        }

        // 需要删除的项目数据集关系列表
        List<Long> deleteModelIdList = new ArrayList<>(dbModelIdList);
        deleteModelIdList.removeAll(modelIdSet);
        if(!CollectionUtils.isEmpty(deleteModelIdList)) {
            modelMapper.deleteProjectModelRelation(targetProjectId, deleteModelIdList);
        }

        // 需要新增的项目数据集关系列表
        List<Long> insertModelIdList = new ArrayList<>(modelIdSet);
        insertModelIdList.removeAll(dbModelIdList);
        if(!CollectionUtils.isEmpty(insertModelIdList)) {
            long now = System.currentTimeMillis();
            List<ProjectModelDto> projectModelRelationList = new ArrayList<>();
            insertModelIdList.forEach(modelId -> {
                ProjectModelDto projectModelRelation = new ProjectModelDto();
                projectModelRelation.setModelId(modelId);
                projectModelRelation.setProjectId(targetProjectId);
                projectModelRelation.setCreateTime(now);
                projectModelRelation.setUpdateTime(now);
                projectModelRelationList.add(projectModelRelation);
            });
            modelMapper.batchInsertProjectModelRelation(projectModelRelationList);
        }
    }

	/**
	 * @Description 创建项目和数据集关系
	 * @param projectId : 项目ID
	 * @param datasetIdList : 数据集ID集合
	 * @author lizi
	 * @date 2018/12/4 下午4:16
	 */
	private void insertProjectDataSetRelation(Long projectId, List<Long> datasetIdList) {
		// 需要新增的项目数据集关系列表
		if(!CollectionUtils.isEmpty(datasetIdList)) {
			long now = System.currentTimeMillis();
			List<PaiProjectDatasetRelation> projectDatasetRelationList = new ArrayList<>();
			datasetIdList.forEach(datasetId -> {
				PaiProjectDatasetRelation projectDatasetRelation = new PaiProjectDatasetRelation();
				projectDatasetRelation.setDatasetId(datasetId);
				projectDatasetRelation.setProjectId(projectId);
				projectDatasetRelation.setCreateTime(now);
				projectDatasetRelation.setUpdateTime(now);
				projectDatasetRelationList.add(projectDatasetRelation);
			});
			paiDataSetMapper.batchInsertProjectDatasetRelation(projectDatasetRelationList);
		}
	}

	/**
	 * @Description 生成复制后的项目名称
	 * @param projectName : 原项目名称
	 * @param projectNameList : 已经存在的项目名称集合
	 *
	 * 定义规则：
	 * projectName = 项目, copyProjectName = 项目-1, copyProjectName = 项目一_copy (1), 以此类推
	 * @author lizi
	 * @date 2018/12/6 上午10:26
	 */
	private String generateProjectName(String projectName, List<String> projectNameList) {
		String copyProjectName = projectName;
		if(!CollectionUtils.isEmpty(projectNameList) && projectNameList.contains(projectName)) {
			// 某文件存在复制副本
			int n = 2;
			copyProjectName = projectName + n;
			while (projectNameList.contains(copyProjectName)) {
				n = n + 1;
				copyProjectName = projectName + n;
			}
		}

		return copyProjectName;
	}

	/**
	 * @Description 初始化公开项目人员信息
	 * @param projectList : 项目列表
	 * @author lizi
	 * @date 2018/12/6 下午7:07
	 */
	private void initPublicProjectUserInfo(List<PublicProjectListDto> projectList) {
		if(CollectionUtils.isEmpty(projectList)) {
			return;
		}

		// 获取公开项目对应的用户ID集合
		List<String> userIdList = projectList.stream().map(PublicProjectListDto::getUserId).collect(Collectors.toList());
		if(CollectionUtils.isEmpty(userIdList)) {
			return;
		}

		// 初始化用户信息
		Response<List<UserInfoDto>> response = requestUserInfo(userIdList);
		ResponseMessage responseMessage = response.getMessage();
		if(responseMessage.getCode() == ResponseMessage.SUCCESS_CODE) {
			List<UserInfoDto> userInfoList = response.getData();
			if(CollectionUtils.isEmpty(userInfoList)) {
				return;
			}
			userInfoList.forEach(user -> {
				projectList.forEach(project -> {
					if(project.getUserId().equals(user.getUserId())) {
						project.setUserName(user.getUsername());
						project.setHeadImage(user.getHeadImage());
					}
				});
			});
		}
	}

	/**
	 * @Description 请求文件中心接口
	 * @param paramMap : 接口参数
	 * @param userInfo : 用户信息
	 * @param url : 请求地址
	 * @author lizi
	 * @date 2018/12/6 上午11:49
	 */
	@Override
	public Response<String> requestFileCenter(MultiValueMap<String, String> paramMap, LoginResultDto userInfo, String url) {
		try {
			// 复制项目代码
			HttpHeaders headers = new HttpHeaders();
			headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
			headers.add(Constant.USER_TOKEN, userInfo.getToken());
			headers.add(Constant.USER_BITA_TOKEN, userInfo.getBitaToken());
			HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(paramMap, headers);
			long start = System.currentTimeMillis();
			ResponseEntity<Response> response = restTemplate.postForEntity(env.getFileCenterUrl() + url, request , Response.class);
			// 请求失败
			if(response.getStatusCode() != HttpStatus.OK) {
				return Response.error(Constant.RESPONSE_STATUS_SUCCESS, ProjectErrorEnum.PROJECT_FILE_COPY_FAILURE.getSeq(), ProjectErrorEnum.PROJECT_FILE_COPY_FAILURE.getDesc(), null);
			}
			int code = response.getBody().getMessage().getCode();
			String message = response.getBody().getMessage().getMessage();
			if(code == ResponseMessage.SUCCESS_CODE || code == ProjectErrorEnum.FILE_EXIST.getSeq()) {
				String projectPath = response.getBody().getData().toString();
				return Response.ok(projectPath);
			} else {
				// 复制失败
				return Response.error(Constant.RESPONSE_STATUS_SUCCESS, code, message, null);
			}
		} catch (Exception e) {
			return Response.error(Constant.RESPONSE_STATUS_SUCCESS, ProjectErrorEnum.PROJECT_FILE_COPY_FAILURE.getSeq(), ProjectErrorEnum.PROJECT_FILE_COPY_FAILURE.getDesc(), null);
		}
	}

	@Override
	public Response<List<Model>> getProjectUseModels(Long projectId) {

		try {
			List<Model> projectUseModels = projectMapper.getProjectUseModels(projectId);
			return Response.ok(projectUseModels);
		}catch (Exception e){
			logger.error("getProjectUseModels error projectId: {}", projectId);
			return Response.error(Constant.RESPONSE_STATUS_SUCCESS, ProjectErrorEnum.GET_PROJECT_MODELS_ERROR.getSeq(),
					ProjectErrorEnum.GET_PROJECT_MODELS_ERROR.getDesc(), null);
		}
	}

	/**
	 * 功能描述：获取公开项目信息
	 * @param userInfo 用户信息
	 * @param projectId 项目id
	 * @return: com.leinao.commons.Response<com.leinao.project.dto.PublicProjectInfo> 公开项目信息
	 * @Author: Guo Liangbo
	 * @Date: 2019/6/4 14:12
	 */
	@Override
	public Response<PublicProjectInfo> publicProjectInfo(LoginResultDto userInfo, Long projectId) {
		try {
			// 查询项目信息
			Project project = projectMapper.getProject(projectId);
			// 检验1.判断项目是否存在
			if(null == project) {
				return Response.error(Constant.RESPONSE_STATUS_SUCCESS, ProjectErrorEnum.INVALID_PROJECT_ID.getSeq(), ProjectErrorEnum.INVALID_PROJECT_ID.getDesc(),null);
			}
			// 检验2.操作人是否项目拥有者，非项目拥有人，不可进行公开操作
			if(!userInfo.getUserId().equals(project.getUserId())) {
				return Response.error(Constant.RESPONSE_STATUS_SUCCESS, ProjectErrorEnum.PROJECT_NO_AUTHORITY.getSeq(), ProjectErrorEnum.PROJECT_NO_AUTHORITY.getDesc(),null);
			}

			//初始化返回结果
			PublicProjectInfo publicProjectInfo = new PublicProjectInfo();

			//从数据库中查询项目公开历史信息
			List<ProjectHistory> projectHistories = projectHistoryMapper.selectProjectHistories(projectId);

			//无公开记录，则设置公开次数为0，公开时间为空
			if(null == projectHistories || projectHistories.size()<=0){
				publicProjectInfo.setPublicCount(0);
				publicProjectInfo.setLastPublicTime(null);
			}else{
				Long lastPublicTime = 0L;
				for (ProjectHistory projectHistory : projectHistories){
					Long createTime = projectHistory.getCreateTime();
					if(lastPublicTime <= createTime){
						lastPublicTime = createTime;
					}
				}
				publicProjectInfo.setPublicCount(projectHistories.size());
				publicProjectInfo.setLastPublicTime(lastPublicTime);
			}

			//从数据库查询项目中的任务信息
			List<PaiProjectJobDto>  jobsInDb = projectMapper.getProjectJobInfo(projectId, null);

			//从底层拿到任务信息
			// 请求任务信息地址拼接
			StringBuilder sb = new StringBuilder(env.getRestServerUrl() + Constant.REST_SERVER_BATCH_QUERY_JOB_API);
			for(PaiProjectJobDto ppj : jobsInDb) {
				logger.debug("jobName: {}", ppj.getJobName());
				sb.append(ppj.getJobName()).append(",");
			}
			String batchQueryJobInfoUrl = sb.toString();
			logger.debug("batchQueryJobInfoUrl: {}", batchQueryJobInfoUrl);
			// 从底层查询出任务的信息
			List<JobInfoDto> jobInfoList = batchQueryJobInfo(batchQueryJobInfoUrl, userInfo.getToken());

			//成功任务信息，要返回给前端使用的
			List<PaiProjectJobDto> successJobs = new ArrayList<>();

			for (PaiProjectJobDto job:jobsInDb){
				for(JobInfoDto jobInfoDto: jobInfoList){
					if(job.getJobName().equals(jobInfoDto.getJobName()) && ProjectJobStateEnum.SUCCEEDED.getState().equals(jobInfoDto.getState())){
						successJobs.add(job);
					}
				}
			}
			publicProjectInfo.setJobs(successJobs);
			return Response.ok(Constant.RESPONSE_STATUS_SUCCESS, OpenProjectEnum.GET_PUBLIC_INFO_SUCCESS.getSeq(), OpenProjectEnum.GET_PUBLIC_INFO_SUCCESS.getDesc(), publicProjectInfo);
		}catch (Exception e){
			return Response.error(Constant.RESPONSE_STATUS_SUCCESS, OpenProjectEnum.GET_PUBLIC_INFO_ERROR.getSeq(), OpenProjectEnum.GET_PUBLIC_INFO_ERROR.getDesc(), null);
		}
	}

	/**
	 * @Description 根据用户ID或邮箱获取用户信息
	 * @param userIdOrEmailList : 用户ID或邮箱列表
	 * @author lizi
	 * @date 2018/12/6 上午11:49
	 */
	@SuppressWarnings("unchecked")
	private Response<List<UserInfoDto>> requestUserInfo(List<String> userIdOrEmailList) {
		try {
			// 复制项目代码
			HttpHeaders headers = new HttpHeaders();
			headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
			StringBuilder urlBuilder = new StringBuilder(env.getBitahubServiceUrl()).append(Constant.BITAHUB_USER_INFO_GET_API).append("?");
			for(String userIdOrEmail : userIdOrEmailList) {
				urlBuilder.append("userIdOrEmailList=").append(userIdOrEmail).append("&");
			}
			urlBuilder.delete(urlBuilder.length() - 1, urlBuilder.length());
			logger.info("requestUserInfo url: {}", urlBuilder);
			ResponseEntity<Map> response = restTemplate.getForEntity(urlBuilder.toString(), Map.class);
			// 请求失败
			if(response.getStatusCode() != HttpStatus.OK) {
				logger.info("request user info failure, userIdList: {}, StatusCode : {}", userIdOrEmailList, response.getStatusCode());
				return Response.error(Constant.RESPONSE_STATUS_SUCCESS, ProjectErrorEnum.USER_INFO_GET_FAILURE.getSeq(), ProjectErrorEnum.USER_INFO_GET_FAILURE.getDesc(), null);
			}
			Map responseMap = response.getBody();
			logger.info("request user info result, responseMap: {}, userIdOrEmailList: {}", responseMap, userIdOrEmailList);
			if(responseMap == null) {
				return Response.error(Constant.RESPONSE_STATUS_SUCCESS, ProjectErrorEnum.USER_INFO_GET_FAILURE.getSeq(), ProjectErrorEnum.USER_INFO_GET_FAILURE.getDesc(), null);
			}

			// 解析请求结果
			Integer code = (Integer)responseMap.get("code");
			if(code != null && code == ResponseMessage.SUCCESS_CODE) {
				List<UserInfoDto> userInfoList = new ArrayList<>();
				List<Map> resultMap = (List<Map>)responseMap.get("result");
				if(!CollectionUtils.isEmpty(resultMap)) {
					resultMap.forEach(result -> {
						UserInfoDto userInfoDto = new UserInfoDto();
						userInfoDto.setUserId((String)result.get("userId"));
						userInfoDto.setUsername((String)result.get("username"));
						userInfoDto.setHeadImage((String)result.get("headImage"));
						userInfoList.add(userInfoDto);
					});
					return Response.ok(userInfoList);
				}
			}
			return Response.error(Constant.RESPONSE_STATUS_SUCCESS, ProjectErrorEnum.USER_INFO_GET_FAILURE.getSeq(), ProjectErrorEnum.USER_INFO_GET_FAILURE.getDesc(), null);
		} catch (Exception e) {
			logger.error("requestUserInfo Exception", e);
			return Response.error(Constant.RESPONSE_STATUS_SUCCESS, ProjectErrorEnum.USER_INFO_GET_FAILURE.getSeq(), ProjectErrorEnum.USER_INFO_GET_FAILURE.getDesc(), null);
		}
	}

	/**
	 * @Description 修改项目配置信息
	 * @param config : 项目配置信息
     * @param config : 项目原始所属用户ID
     * @param config : 项目复制后的用户ID
	 * @author lizi
	 * @date 2018/12/13 下午7:07
	 */
	private String modifyProjectConfig(String config) {
		if(StringUtils.isEmpty(config)) {
			return config;
		}

		// 解析项目配置，Feature.OrderedField参数不改变原有配置顺序
		JSONObject json = JSON.parseObject(config, Feature.OrderedField);

		// 修改job名称
		String jobName = json.getString(Constant.CONFIG_JOB_NAME);
		logger.info("config property of jobName: {}", jobName);
		if(!StringUtils.isEmpty(jobName)) {
            // 生成新的jobName
            String primaryCode = RandomPrimaryCode.getPrimaryCode(6);
            logger.debug("create jobName primaryCode: {}", primaryCode);
            if(jobName.contains("-")) {
                jobName = jobName.substring(0, jobName.lastIndexOf("-") + 1) + primaryCode;
            } else {
                jobName = jobName + "-" + primaryCode;
            }
            json.put(Constant.CONFIG_JOB_NAME, jobName);
		}

        // 修改output
		json.put(Constant.CONFIG_OUTPUT, new HashMap<>());

		return json.toJSONString();
	}

	/**
	 * 功能描述：获取公开项目信息
	 * @param sortType 排序方式
	 * @param cp 当前页
	 * @param ps  每页条数
	 * @return com.leinao.commons.Response<com.leinao.util.page.PageInfo>
	 * @Author: guoliangbo
	 * @Date: 2019/5/7 13:24
	 */
	@Override
    public Response<PageInfo> getOpenProjectInfo(Integer sortType,  Integer cp, Integer ps) {
        // 设置分页条件
        PageHelper.startPage(cp, ps);

        List<PublicProjectListDto> projectList = projectMapper.getPublicProjectList(sortType, null);

		return Response.ok(new PageInfo<>(projectList == null ? Collections.emptyList() : projectList));
    }

	/**
	 * 功能描述：项目名是否可用
	 * @param projectName 项目名
	 * @param userInfo 用户信息
	 * @return com.leinao.commons.Response<java.lang.Void>
	 * @Author: guoliangbo
	 * @Date: 2019/5/7 13:23
	 */
	@Override
	public Response<Void> isUsable4Name(String projectName, LoginResultDto userInfo) {
		try {
			String pname = projectMapper.isUsable4Name(userInfo.getUserId(), projectName);
			if (StringUtils.isNotBlank(pname)) {
				return Response.ok(Constant.RESPONSE_STATUS_SUCCESS, ProjectEnum.PROJECT_NAME_USABLE.getSeq(), "项目名可用");
			}
			return Response.ok(Constant.RESPONSE_STATUS_SUCCESS, ProjectEnum.PROJECT_NAME_DISABLED.getSeq(), "项目名不可用");
		} catch (Exception e) {
			logger.error(e.getMessage(), e);
			return Response.ok(Constant.RESPONSE_STATUS_SUCCESS, ProjectEnum.PROJECT_NAME_DISABLED.getSeq(), "项目名不可用");
		}
	}

	/**
	 * @Description 搜索公开项目列表
	 * @param search : 搜索内容
	 * @param pageNumber : 当前页
	 * @param pageSize : 每页条数
	 * @author lizi
	 * @date 2019/02/26 下午5:17
	 */
	@Override
	public Response<PageInfo> searchPublicProjectList(String search, Integer pageNumber, Integer pageSize) {
		// 设置分页条件
		PageHelper.startPage(pageNumber, pageSize);

		// 数据集项目列表
		List<PublicProjectListDto> projectList = projectMapper.searchPublicProjectList(search);

		// 初始化公开项目人员信息
		initPublicProjectUserInfo(projectList);

		return Response.ok(new PageInfo<>(projectList == null ? Collections.emptyList() : projectList));
	}

	/**
	 * @Description 搜索公开项目列表
	 * @author lizi
	 * @date 2019/03/05 下午5:17
	 */
	@Override
	public Response<ProjectJobStatisticsDto> getTaskStatistics(LoginResultDto userInfo) {
		ProjectJobStatisticsDto projectJobStatisticsDto = new ProjectJobStatisticsDto();

		// 数据集项目任务列表
		List<ProjectJobViewDto> projectJobViewList = getProjectJobList(userInfo);
		if(CollectionUtils.isNotEmpty(projectJobViewList)) {
			projectJobViewList.forEach(projectJobViewDto -> {
				ProjectJobStateEnum jobStateEnum = ProjectJobStateEnum.enumOf(projectJobViewDto.getState());
				if(jobStateEnum == null) {
					return;
				}
				switch(jobStateEnum){
					case WAITING:
						projectJobStatisticsDto.setWaitingNum(projectJobStatisticsDto.getWaitingNum() + 1);
						break;
					case RUNNING:
						projectJobStatisticsDto.setRunningNum(projectJobStatisticsDto.getRunningNum() + 1);
						break;
					case STOPPING:
						projectJobStatisticsDto.setStoppingNum(projectJobStatisticsDto.getStoppingNum() + 1);
						break;
					case STOPPED:
						projectJobStatisticsDto.setStoppedNum(projectJobStatisticsDto.getStoppedNum() + 1);
						break;
					case FAILED:
						projectJobStatisticsDto.setFailedNum(projectJobStatisticsDto.getFailedNum() + 1);
						break;
					case SUCCEEDED:
						projectJobStatisticsDto.setSucceededNum(projectJobStatisticsDto.getSucceededNum() + 1);
						break;
					default:
						break;
				}
			});
		}

		return Response.ok(projectJobStatisticsDto);
	}

	/**
	 * @Description 获取项目任务信息
	 * @author lizi
	 * @date 2019/03/05 下午5:17
	 */
	private List<ProjectJobViewDto> getProjectJobList(LoginResultDto userInfo) {
		// 数据集项目任务列表
		List<ProjectJobViewDto> projectJobViewList = paiProjectJobMapper.getTaskViewList(userInfo.getUserId());

		// 任务状态设置
		if(CollectionUtils.isNotEmpty(projectJobViewList)) {
			StringBuilder batchQueryJobBuilder = new StringBuilder(env.getRestServerUrl() + Constant.REST_SERVER_BATCH_QUERY_JOB_API);
			for(ProjectJobViewDto projectJobViewDto : projectJobViewList) {
				logger.debug("jobName: {}", projectJobViewDto.getJobName());
				batchQueryJobBuilder.append(projectJobViewDto.getJobName()).append(",");
			}
			String batchQueryJobUrl = batchQueryJobBuilder.toString();
			batchQueryJobUrl = batchQueryJobUrl.substring(0, batchQueryJobUrl.length() - 1);
			logger.debug("batchQueryJobUrl: {}", batchQueryJobUrl);
			List<JobInfoDto> jobInfoList = batchQueryJobInfo(batchQueryJobUrl, userInfo.getToken());
			if(CollectionUtils.isNotEmpty(jobInfoList)) {
				Map<String, JobInfoDto> jobInfoMap = jobInfoList.stream().collect(Collectors.toMap(JobInfoDto::getJobName,jobInfoDto -> jobInfoDto,(oldValue,newValue) -> oldValue));
				projectJobViewList.forEach(projectJobViewDto -> {
					JobInfoDto jobInfoDto = jobInfoMap.get(projectJobViewDto.getJobName());
					if(jobInfoDto != null) {
						projectJobViewDto.setState(jobInfoDto.getState());
						projectJobViewDto.setExecutionType(jobInfoDto.getExecutionType());
						projectJobViewDto.setRetries(jobInfoDto.getRetries());
						projectJobViewDto.setCreateTime((jobInfoDto.getCreatedTime()));
						projectJobViewDto.setCompletedTime(jobInfoDto.getCompletedTime());
						projectJobViewDto.setUserId(jobInfoDto.getUserId());
						projectJobViewDto.setTensorboardUrl(jobInfoDto.getTensorboardUrl());
					}
				});
			}
		}

		// 移除状态未知的任务
		projectJobViewList.removeIf(projectJobView -> StringUtils.isEmpty(projectJobView.getState()));

		return projectJobViewList;
	}
	/**
	 * @Description 获取项目任务信息
	 * @author lizi
	 * @date 2019/03/05 下午5:17
	 */
	private List<ProjectJobViewDto> getProjectJobListForTag(LoginResultDto userInfo,String jobTag) {
		// 数据集项目任务列表
		List<ProjectJobViewDto> projectJobViewList = paiProjectJobMapper.getTaskViewListForTag(userInfo.getUserId(),jobTag);

		// 任务状态设置
		if(CollectionUtils.isNotEmpty(projectJobViewList)) {
			StringBuilder batchQueryJobBuilder = new StringBuilder(env.getRestServerUrl() + Constant.REST_SERVER_BATCH_QUERY_JOB_API);
			for(ProjectJobViewDto projectJobViewDto : projectJobViewList) {
				logger.debug("jobName: {}", projectJobViewDto.getJobName());
				batchQueryJobBuilder.append(projectJobViewDto.getJobName()).append(",");
			}
			String batchQueryJobUrl = batchQueryJobBuilder.toString();
			batchQueryJobUrl = batchQueryJobUrl.substring(0, batchQueryJobUrl.length() - 1);
			logger.debug("batchQueryJobUrl: {}", batchQueryJobUrl);
			List<JobInfoDto> jobInfoList = batchQueryJobInfo(batchQueryJobUrl, userInfo.getToken());
			if(CollectionUtils.isNotEmpty(jobInfoList)) {
				Map<String, JobInfoDto> jobInfoMap = jobInfoList.stream().collect(Collectors.toMap(JobInfoDto::getJobName,jobInfoDto -> jobInfoDto,(oldValue,newValue) -> oldValue));
				projectJobViewList.forEach(projectJobViewDto -> {
					JobInfoDto jobInfoDto = jobInfoMap.get(projectJobViewDto.getJobName());
					if(jobInfoDto != null) {
					    projectJobViewDto.setJobTag(projectJobViewDto.getJobTag());
					    projectJobViewDto.setRemark(projectJobViewDto.getRemark());
						projectJobViewDto.setState(jobInfoDto.getState());
						projectJobViewDto.setExecutionType(jobInfoDto.getExecutionType());
						projectJobViewDto.setRetries(jobInfoDto.getRetries());
						projectJobViewDto.setCreateTime((jobInfoDto.getCreatedTime()));
						projectJobViewDto.setCompletedTime(jobInfoDto.getCompletedTime());
						projectJobViewDto.setUserId(jobInfoDto.getUserId());
						projectJobViewDto.setTensorboardUrl(projectJobViewDto.getTensorboardUrl());
						projectJobViewDto.setTimeConsuming(jobInfoDto.getTimeConsuming());
					}
				});
			}
		}

		// 移除状态未知的任务
		projectJobViewList.removeIf(projectJobView -> StringUtils.isEmpty(projectJobView.getState()));

		return projectJobViewList;
	}

	/**
	 * @Description 获取公开项目事例
	 * @author lizi
	 * @date 2019/03/13 下午5:31
	 */
	@Override
	public Response<PublicProjectExampleDto> getPublicProjectExample() {
		Long exampleProjectId = env.getExampleProjectId();
		String exampleProjectJobIds = env.getExampleProjectJobIds();
		// 获取公开项目事例信息
		PublicProjectExampleDto projectExampleDto = projectMapper.getPublicProjectExample(exampleProjectId);
		if(projectExampleDto == null) {
			return Response.error(Constant.RESPONSE_STATUS_SUCCESS, ProjectErrorEnum.EXAMPLE_PROJECT_NOT_EXISTS.getSeq(), ProjectErrorEnum.EXAMPLE_PROJECT_NOT_EXISTS.getDesc(), null);
		}

		// 设置公开任务ID
		projectExampleDto.setJobIds(exampleProjectJobIds);

		// 初始化公开项目人员信息
		List<PublicProjectListDto> projectList = new ArrayList<>();
		PublicProjectListDto publicProjectListDto = new PublicProjectListDto();
		publicProjectListDto.setId(projectExampleDto.getId());
		publicProjectListDto.setUserId(projectExampleDto.getUserId());
		projectList.add(publicProjectListDto);
		initPublicProjectUserInfo(projectList);

		projectExampleDto.setUserName(publicProjectListDto.getUserName());
		projectExampleDto.setHeadImage(publicProjectListDto.getHeadImage());

		// 初始化公开项目分类信息
		initPublicProjectCategoryInfo(projectList, 0L);
		projectExampleDto.setCategoryList(publicProjectListDto.getCategoryList());

		return Response.ok(projectExampleDto);
	}

	/**
	  * @Description 	获取用户项目详情
	  * @param projectId 项目Id
	  * @return
	  * @author:    weiwei
	  * @Date:  2019/3/26 10:38
	  */
	@Override
	public Response<Project> getUserProjectDetail(Long projectId, LoginResultDto userInfo) {

		// 获取项目信息
		Project project = projectMapper.getUserProjectDetail(projectId);
		if(project == null) {
			return Response.error(Constant.RESPONSE_STATUS_SUCCESS, ProjectErrorEnum.INVALID_PROJECT_ID.getSeq(), ProjectErrorEnum.INVALID_PROJECT_ID.getDesc(), null);
		}

		// 项目非用户自己的项目
		if(!userInfo.getUserId().equals(project.getUserId())) {
			return Response.ok(Constant.RESPONSE_STATUS_SUCCESS, ProjectErrorEnum.PROJECT_NO_AUTHORITY.getSeq(), ProjectErrorEnum.PROJECT_NO_AUTHORITY.getDesc(), null);
		}

		return Response.ok(project);
	}

	/**
	  * @Description 获取用户任务详情
	  * @param jobId	任务ID
	  * @param userInfo	用户信息
	  * @return
	  * @author:    weiwei
	  * @Date:  2019/3/26 13:40
	  */
	@Override
	public Response<ProjectJobViewDto> getUserTaskDetail(Long jobId,  LoginResultDto userInfo) {
		ProjectJobViewDto jobInfoDto = projectMapper.getUserTaskDetail(jobId);
		logger.debug("jobInfoDto info: {}", jobInfoDto);
		if(jobInfoDto == null){
			return Response.ok(Constant.RESPONSE_STATUS_SUCCESS, ProjectJobHandleEnum.GET_ERROR.getSeq(), ProjectJobHandleEnum.GET_ERROR.getDesc(), null);
		}
		if(!jobInfoDto.getUserId().equals(userInfo.getUserId())) {
			return Response.ok(Constant.RESPONSE_STATUS_SUCCESS, ProjectErrorEnum.PROJECT_NO_AUTHORITY.getSeq(), ProjectErrorEnum.PROJECT_NO_AUTHORITY.getDesc(), null);
		}

		try {
			// 获取底层任务状态
			String getUserTaskDetailUrl = env.getRestServerUrl() + Constant.REST_SERVER_BATCH_QUERY_JOB_API + jobInfoDto.getJobName();
			logger.debug("getUserTaskDetailUrl: {}", getUserTaskDetailUrl);
			List<JobInfoDto> jobInfoList = batchQueryJobInfo(getUserTaskDetailUrl, userInfo.getToken());
			logger.info("request getJobDetail return:{}", JSON.toJSON(jobInfoList));
			if (CollectionUtils.isEmpty(jobInfoList)) {
				return Response.ok(Constant.RESPONSE_STATUS_SUCCESS, ProjectJobHandleEnum.LOAD_JOB_INFO_ERROR.getSeq(), ProjectJobHandleEnum.LOAD_JOB_INFO_ERROR.getDesc(), jobInfoDto);
			}

			JobInfoDto jobInfo = jobInfoList.get(0);
			//任务创建时间
			jobInfoDto.setTaskCreateTime(jobInfoDto.getCreateTime());
			//任务状态
			jobInfoDto.setState(jobInfo.getState());
            //任务执行状态
            jobInfoDto.setExecutionType(jobInfo.getExecutionType());
			//任务容器完成的时间
			jobInfoDto.setCompletedTime(jobInfo.getCompletedTime());
			//任务创建容器的时间
			jobInfoDto.setCreateTime(jobInfo.getCreatedTime());
			//任务用时
			jobInfoDto.setTimeConsuming(jobInfo.getTimeConsuming());

			return Response.ok(Constant.RESPONSE_STATUS_SUCCESS, ProjectJobHandleEnum.GET_SUCCESS.getSeq(), ProjectJobHandleEnum.GET_SUCCESS.getDesc(), jobInfoDto);
		} catch (Exception e) {
			logger.error("loadJobDetail error", e);
			return Response.ok(Constant.RESPONSE_STATUS_SUCCESS, ProjectJobHandleEnum.LOAD_JOB_INFO_ERROR.getSeq(), ProjectJobHandleEnum.LOAD_JOB_INFO_ERROR.getDesc(), jobInfoDto);
		}
	}


	/**
	  * 功能描述: 添加任务标签
	  * @param projectId 项目ID
	  * @param jobId 任务ID
	  * @param jobTag 任务标签
	  * @Return:com.leinao.commons.Response<com.leinao.project.model.Project>
	  * @Author:HuoPengfei
	  * @Date:2019/5/15 18:47
	  */
	@Override
	public void saveJobTag(Long projectId, Long jobId, String userId,String jobTag) {

		Long time = System.currentTimeMillis();
		projectMapper.saveJobTag(projectId,jobId,userId,jobTag,time,time);
	}
    /**
      * 功能描述: 修改标签
      * @param projectId
      * @param jobId
      * @param userId
      * @param jobTag
      * @Return:void
      * @Author:HuoPengfei
      * @Date:2019/5/27 14:17
      */
    @Override
    public void updateJobTag(Long projectId, Long jobId, String userId, String jobTag) {
        projectMapper.updateJobTag(projectId,jobId,userId,jobTag);
    }

    /**
	  * 功能描述: 标签列表
	  * @param projectId
	  * @Return:com.leinao.commons.Response<java.util.List<com.leinao.job.dto.JobTagDto>>
	  * @Author:HuoPengfei
	  * @Date:2019/5/16 17:43
	  */
	@Override
	public Response<List<JobTagDto>> getjobTagListByProId(Long projectId) {
        List<JobTagDto> jobTagDtos = projectMapper.getjobTagListByProId(projectId);
        return Response.ok(jobTagDtos);
	}
	/**
	  * 功能描述: 标签列表
	  * @param userId
	  * @Return:com.leinao.commons.Response<java.util.List<com.leinao.job.dto.JobTagDto>>
	  * @Author:HuoPengfei
	  * @Date:2019/5/16 17:43
	  */
	@Override
	public Response<List<JobTagDto>> getjobTagListByUserId(String userId) {
		List<JobTagDto> jobTagList = projectMapper.getjobTagListByUserId(userId);
		return Response.ok(jobTagList);
	}


	/**
	 * 功能描述：待公开项目校验私有数据集、私有模型
	 * @param userId 用户id
	 * @param id 项目id
	 * @return com.leinao.project.dto.ProjectPrivateInfo 返回项目私有信息
	 * @Author: guoliangbo
	 * @Date: 2019/6/6 15:16
	 */
	@Override
	public Response<ProjectPrivateInfo> getPrivateInfo(String userId,Long id) {
		//查询私有数据集情况
        List<PrivateDataSetDto> dataSets = projectMapper.getIdFindDataset(userId,id);

        //查询私有模型列表
        List<ModelDto> models = projectMapper.getPrivateModelByParams(userId,id);

        //返回给前端的数据，包括模型和数据集
		ProjectPrivateInfo projectPrivateInfo = new ProjectPrivateInfo();

        //私有数据集和模型都为空的话，直接返回前端
		if( (null == dataSets || dataSets.size() <=0) && (null == models || models.size() <= 0)){
            return Response.ok(projectPrivateInfo);
        }else if(dataSets.size() != 0 && models.size() != 0){
            projectPrivateInfo.setDataSets(dataSets);
            projectPrivateInfo.setModels(models);
            return Response.error(Constant.RESPONSE_STATUS_SUCCESS, ProjectErrorEnum.PROJECT_CONTAIN_PRIVATE_MODEL_AND_DATASET.getSeq(), ProjectErrorEnum.PROJECT_CONTAIN_PRIVATE_MODEL_AND_DATASET.getDesc(),projectPrivateInfo);
        }else if(dataSets.size() != 0){
            projectPrivateInfo.setDataSets(dataSets);
            return Response.error(Constant.RESPONSE_STATUS_SUCCESS, ProjectErrorEnum.PROJECT_CONTAIN_PRIVATE_DATASET.getSeq(), ProjectErrorEnum.PROJECT_CONTAIN_PRIVATE_DATASET.getDesc(),projectPrivateInfo);
        }else{
		    projectPrivateInfo.setModels(models);
            return Response.error(Constant.RESPONSE_STATUS_SUCCESS, ProjectErrorEnum.PROJECT_CONTAIN_PRIVATE_MODEL.getSeq(), ProjectErrorEnum.PROJECT_CONTAIN_PRIVATE_MODEL.getDesc(),projectPrivateInfo);
        }
	}




	/**
	 * 功能描述：根据用户id 查询用户项目数据
	 * @param projectId 项目id
	 * @param userId 用户id
	 * @Return:com.leinao.commons.Response<java.util.List<com.leinao.project.dto.ProjectInfoDto>> 返回结果
	 * @Author: Guo Liangbo
	 * @Date:2019/5/19 16:44
	 */
	@Override
	public Response<ProjectInfoDto> getProjectOutputs(Long projectId,String userId) {
		try {
			List<ProjectInfoDto> projects = projectMapper.getProjectsByParams(projectId,userId);
			//判断是否有项目，如无直接返回无
			if( null == projects || 0 == projects.size()){
				return Response.ok(Constant.RESPONSE_STATUS_SUCCESS,ProjectEnum.USER_HAS_NO_PROJECT.getSeq(),ProjectEnum.USER_HAS_NO_PROJECT.getDesc(),null);
			}

            List<PaiProjectJobDto> jobs = projectMapper.getProjectJobInfo(projectId,null);
            ProjectInfoDto project = projects.get(0);
            if(null != jobs && null != project){
                for(PaiProjectJobDto job:jobs){
                    //项目代码路径
                    String filePath = project.getFilePath();
                    //输出结果目录
                    String output =  filePath.substring(0,filePath.lastIndexOf("/")+1) + "outputs/"+ job.getCodeNo();
                    //设置进入任务属性
                    job.setOutputPath(output);
                }
                project.setJobs(jobs);
            }else{
                return Response.ok(Constant.RESPONSE_STATUS_SUCCESS,ProjectEnum.PROJECT_HAS_NO_JOB.getSeq(),ProjectEnum.PROJECT_HAS_NO_JOB.getDesc(),null);
            }
			return  Response.ok(Constant.RESPONSE_STATUS_SUCCESS,ProjectEnum.GET_OUTPUTS_SUCCESS.getSeq(),ProjectEnum.GET_OUTPUTS_SUCCESS.getDesc(),project);
		}catch (Exception e){
			logger.error(e.getMessage(), e);
			return Response.ok(Constant.RESPONSE_STATUS_SUCCESS, ProjectJobHandleEnum.GET_ERROR.getSeq(), ProjectJobHandleEnum.GET_ERROR.getDesc(), null);
		}
	}

    /**
     * 功能描述：项目引用output Info
     * @param userId 用户id
     * @param projectId 项目id
     * @return com.leinao.commons.Response<com.leinao.project.dto.ProjectInfoDto> 返回引用项目信息
     * @Author: guoliangbo
     * @Date: 2019/5/21 13:41
     */
    @Override
    public Response<List<ProjectInfoDto>> projectQuoteInfo(String userId, Long projectId) {

        //不传入项目id，查询所有项目
        List<ProjectInfoDto> projects = projectMapper.getProjectsByParams(null,userId);
        //判断是否有项目，如无直接返回无
        if( null == projects || 0 == projects.size()){
            return Response.ok(Constant.RESPONSE_STATUS_SUCCESS,ProjectEnum.USER_HAS_NO_PROJECT.getSeq(),ProjectEnum.USER_HAS_NO_PROJECT.getDesc(),null);
        }
        //抽出本身项目
        ProjectInfoDto curProject = new ProjectInfoDto();
        //排除本身项目
        for(ProjectInfoDto projectInfo:projects){
            if(projectId.equals(projectInfo.getId())){
                curProject = projectInfo;
            }
        }
        //引用项目id
        Long quoteProjectId = curProject.getQuoteProjectId();
        //如果引用项目id不为空，进行标记引用项目和任务
        if(null != quoteProjectId){
            //取出本身项目的引用项目信息
            for(ProjectInfoDto projectInfo:projects){
                if(quoteProjectId.equals(projectInfo.getId())){
                    projectInfo.setChechMark(true);
                    List<PaiProjectJobDto> jobs = projectMapper.getProjectJobInfo(quoteProjectId,null);
                    for(PaiProjectJobDto job:jobs){
                        //项目代码路径
                        String filePath = projectInfo.getFilePath();
                        //输出结果目录
                        String output =  filePath.substring(0,filePath.lastIndexOf("/")+1) + "outputs/"+ job.getCodeNo();
                        //设置进入任务属性
                        job.setOutputPath(output);
                        //选中输出项目
                        if(curProject.getQuoteProjectJobId().equals(job.getId())){
                            job.setCheckMark(true);
                        }
                    }
                    projectInfo.setJobs(jobs);
                }
            }
            return Response.ok(Constant.RESPONSE_STATUS_SUCCESS,ProjectEnum.GET_QUOTE_OUTPUTS_SUCCESS.getSeq(),ProjectEnum.GET_QUOTE_OUTPUTS_SUCCESS.getDesc(),projects);
        }else{
            return Response.ok(Constant.RESPONSE_STATUS_SUCCESS,ProjectEnum.QUOTE_OUTPUT_IS_NULL.getSeq(),ProjectEnum.QUOTE_OUTPUT_IS_NULL.getDesc(),projects);
        }

    }


	/**
	 * 功能描述：获取最近新建的jupyter调试任务配置
	 * @param userId 用户ID
	 * @Author: lizi
	 * @Date: 2019/6/5 22:21
	 */
	@Override
	public Response<String> getLastJupyterJobConfig(String userId) {
		String config = projectMapper.getLastJupyterJobConfig(userId);
		return Response.ok(config);
	}

	/**
	 * @Description 初始化公开项目分类信息
	 * @param projectList : 公开项目信息
	 * @param categoryId : 标签Id
	 * @author lizi
	 * @date 2018/12/6 下午7:07
	 */
	private void initPublicProjectCategoryInfo(List<PublicProjectListDto> projectList, Long categoryId) {
		if(CollectionUtils.isEmpty(projectList)) {
			return;
		}

		// 获取公开项目对应的项目ID集合
		List<Long> projectIdList = projectList.stream().map(PublicProjectListDto::getId).collect(Collectors.toList());
		List<CategoryRelationDto> categoryRelationList = categoryMapper.getCategoryListByObjectIdListAndType(projectIdList, CategoryRelationTypeEnum.PROJECT.getType());
		if(CollectionUtils.isEmpty(categoryRelationList)) {
			return;
		}

		//匹配项目对应分类集合
		for(int i = 0; i < projectList.size(); i ++){
            for(int j = 0; j < categoryRelationList.size(); j ++){
                if(projectList.get(i).getId().equals(categoryRelationList.get(j).getObjId())) {
                    if(categoryId.equals(categoryRelationList.get(j).getCategoryId())){
                        CategoryRelationDto first = categoryRelationList.get(0);
                        projectList.get(i).getCategoryList().add(0,categoryRelationList.get(j));
                    }else {
                        projectList.get(i).getCategoryList().add(categoryRelationList.get(j));
                    }
                }
            }
		}
	}
}